diff --git a/Changes.md b/Changes.md index 29ed9feb47..27320fb7f1 100644 --- a/Changes.md +++ b/Changes.md @@ -1,7 +1,81 @@ `*` means potential break changes -# 8.4.0 -- #4848 #4847 #4844 #4836 #4826 #4824 +# 8.4.1 + +- Syntax submodule upgrades from 7f5c968 to 7cc70c9 +- #4856 #4858 + Improve code generation for pattern match: + Input: + ```res + type t = + | A + | B + | C + | D (int ) + | E (int) + + let f = x => { + switch x { + | A => 0 + | B => 1 + | C => 2 + | D (x) => x + | E (x) => x + 1 + } + } + ``` + Output was: + ```js + function f(x) { + if (typeof x !== "number") { + if (x.TAG) { + return x._0 + 1 | 0; + } else { + return x._0; + } + + switch (x) { + case /* A */0 : + return 0; + case /* B */1 : + return 1; + case /* C */2 : + return 2; + } + } + ``` + + Now: + ```js + function f(x) { + if (typeof x !== "number") { + if (x.TAG === /* D */0) { + return x._0; + } else { + return x._0 + 1 | 0; + } + } + switch (x) { + case /* A */0 : + return 0; + case /* B */1 : + return 1; + case /* C */2 : + return 2; + + } + } + ``` + + + +- #4855 *internal changes* + changes to compiler-libs will trigger a rebuild of the compiler, this allows us to + see how changes of compiler-libs affect bsc.exe quickly + +- #4850 replace ocp-ocamlres with a lightweight nodejs script, get rid of such dev dependency + +- #4854 #4848 #4847 #4844 #4836 #4826 #4824 Pinned packages support and `-make-world` respect changes of dependencies diff --git a/darwin/ninja.exe b/darwin/ninja.exe index 1794707600..8e2b48db86 100755 Binary files a/darwin/ninja.exe and b/darwin/ninja.exe differ diff --git a/jscomp/artifacts.json b/jscomp/artifacts.json index 9e3648e942..07bc147654 100644 --- a/jscomp/artifacts.json +++ b/jscomp/artifacts.json @@ -1007,6 +1007,7 @@ "littlecase.js", "ninja.js", "ninjaFactory.js", + "pack.js", "prebuilt.js", "prepublish.js", "release.js", diff --git a/jscomp/common/bs_version.ml b/jscomp/common/bs_version.ml index 91cf0d020a..dbaf0fbd0b 100644 --- a/jscomp/common/bs_version.ml +++ b/jscomp/common/bs_version.ml @@ -22,7 +22,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "8.4.0-dev.1" +let version = "8.4.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = "bs-platform" diff --git a/lib/4.06.1/bsb.ml b/lib/4.06.1/bsb.ml index bd9b7f0d69..1c662ca3c3 100644 --- a/lib/4.06.1/bsb.ml +++ b/lib/4.06.1/bsb.ml @@ -55,7 +55,7 @@ end = struct * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "8.4.0-dev.1" +let version = "8.4.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = "bs-platform" diff --git a/lib/4.06.1/unstable/js_compiler.ml b/lib/4.06.1/unstable/js_compiler.ml index f50b25577c..d2f50b279a 100644 --- a/lib/4.06.1/unstable/js_compiler.ml +++ b/lib/4.06.1/unstable/js_compiler.ml @@ -18117,7 +18117,7 @@ end = struct * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "8.4.0-dev.1" +let version = "8.4.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = "bs-platform" diff --git a/lib/4.06.1/unstable/js_refmt_compiler.ml b/lib/4.06.1/unstable/js_refmt_compiler.ml index 1472eb99ae..02097d59a0 100644 --- a/lib/4.06.1/unstable/js_refmt_compiler.ml +++ b/lib/4.06.1/unstable/js_refmt_compiler.ml @@ -18117,7 +18117,7 @@ end = struct * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "8.4.0-dev.1" +let version = "8.4.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = "bs-platform" diff --git a/lib/4.06.1/whole_compiler.ml b/lib/4.06.1/whole_compiler.ml index 6ff674b182..c58a470ba3 100644 --- a/lib/4.06.1/whole_compiler.ml +++ b/lib/4.06.1/whole_compiler.ml @@ -304589,7 +304589,7 @@ end = struct * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -let version = "8.4.0-dev.1" +let version = "8.4.0" let header = "// Generated by ReScript, PLEASE EDIT WITH CARE" let package_name = "bs-platform" @@ -416063,6 +416063,7 @@ end module Res_minibuffer : sig #1 "res_minibuffer.mli" type t +val add_char : t -> char -> unit val add_string : t -> string -> unit val contents : t -> string val create : int -> t @@ -416130,6 +416131,7 @@ val nil: t val line: t val hardLine: t val softLine: t +val literalLine: t val text: string -> t val concat: t list -> t val indent: t -> t @@ -416137,6 +416139,9 @@ val ifBreaks: t -> t -> t val lineSuffix: t -> t val group: t -> t val breakableGroup: forceBreak : bool -> t -> t +(* `customLayout docs` will pick the layout that fits from `docs`. + * This is a very expensive computation as every layout from the list + * will be checked until one fits. *) val customLayout: t list -> t val breakParent: t val join: sep: t -> t list -> t @@ -416160,8 +416165,30 @@ val equal: t val trailingComma: t val doubleQuote: t +(* + * `willBreak doc` checks whether `doc` contains forced line breaks. + * This is more or less a "workaround" to make the parent of a `customLayout` break. + * Forced breaks are not propagated through `customLayout`; otherwise we would always + * get the last layout the algorithm tries… + * This might result into some weird layouts: + * [fn(x => { + * let _ = x + * }), fn(y => { + * let _ = y + * }), fn(z => { + * let _ = z + * })] + * The `[` and `]` would be a lot better broken out. + * Although the layout of `fn(x => {...})` is correct, we need to break its parent (the array). + * `willBreak` can be used in this scenario to check if the `fn…` contains any forced breaks. + * The consumer can then manually insert a `breakParent` doc, to manually propagate the + * force breaks from bottom to top. + *) +val willBreak: t -> bool + val toString: width: int -> t -> string val debug: t -> unit [@@live] + end = struct #1 "res_doc.ml" module MiniBuffer = Res_minibuffer @@ -416172,6 +416199,9 @@ type lineStyle = | Classic (* fits? -> replace with space *) | Soft (* fits? -> replaced with nothing *) | Hard (* always included, forces breaks in parents *) + (* always included, forces breaks in parents, but doesn't increase indentation + use case: template literals, multiline string content *) + | Literal type t = | Nil @@ -416189,6 +416219,7 @@ let nil = Nil let line = LineBreak Classic let hardLine = LineBreak Hard let softLine = LineBreak Soft +let literalLine = LineBreak Literal let text s = Text s let concat l = Concat l let indent d = Indent d @@ -416224,7 +416255,7 @@ let propagateForcedBreaks doc = (false, doc) | BreakParent -> (true, Nil) - | LineBreak Hard -> + | LineBreak (Hard | Literal) -> (true, doc) | LineBreak (Classic | Soft) -> (false, doc) @@ -416265,6 +416296,14 @@ let propagateForcedBreaks doc = let (_, processedDoc) = walk doc in processedDoc +(* See documentation in interface file *) +let rec willBreak doc = match doc with + | LineBreak (Hard | Literal) | BreakParent | Group {shouldBreak = true} -> true + | Group {doc} | Indent doc | CustomLayout (doc::_) -> willBreak doc + | Concat docs -> List.exists willBreak docs + | IfBreaks {yes; no} -> willBreak yes || willBreak no + | _ -> false + let join ~sep docs = let rec loop acc sep docs = match docs with @@ -416280,7 +416319,7 @@ let rec fits w doc = match doc with | (_ind, _mode, Text txt)::rest -> fits (w - String.length txt) rest | (ind, mode, Indent doc)::rest -> fits w ((ind + 2, mode, doc)::rest) | (_ind, Flat, LineBreak break)::rest -> - if break = Hard then true + if break = Hard || break = Literal then true else let w = if break = Classic then w - 1 else w in fits w rest @@ -416335,9 +416374,14 @@ let toString ~width doc = if mode = Break then ( begin match lineSuffices with | [] -> - MiniBuffer.flush_newline buffer; - MiniBuffer.add_string buffer (String.make ind ' ' [@doesNotRaise]); - process ~pos:ind [] rest + if lineStyle = Literal then ( + MiniBuffer.add_char buffer '\n'; + process ~pos:0 [] rest + ) else ( + MiniBuffer.flush_newline buffer; + MiniBuffer.add_string buffer (String.make ind ' ' [@doesNotRaise]); + process ~pos:ind [] rest + ) | _docs -> process ~pos:ind [] (List.concat [List.rev lineSuffices; cmd::rest]) end @@ -416345,6 +416389,7 @@ let toString ~width doc = let pos = match lineStyle with | Classic -> MiniBuffer.add_string buffer " "; pos + 1 | Hard -> MiniBuffer.flush_newline buffer; 0 + | Literal -> MiniBuffer.add_char buffer '\n'; 0 | Soft -> pos in process ~pos lineSuffices rest @@ -416382,7 +416427,7 @@ let debug t = let rec toDoc = function | Nil -> text "nil" | BreakParent -> text "breakparent" - | Text txt -> text ("text(" ^ txt ^ ")") + | Text txt -> text ("text(\"" ^ txt ^ "\")") | LineSuffix doc -> group( concat [ text "linesuffix("; @@ -416393,6 +416438,7 @@ let debug t = text ")" ] ) + | Concat [] -> text "concat()" | Concat docs -> group( concat [ text "concat("; @@ -416450,6 +416496,7 @@ let debug t = | Classic -> "Classic" | Soft -> "Soft" | Hard -> "Hard" + | Literal -> "Liteal" in text ("LineBreak(" ^ breakTxt ^ ")") | Group {shouldBreak; doc} -> @@ -416459,7 +416506,7 @@ let debug t = indent ( concat [ line; - text ("shouldBreak: " ^ (string_of_bool shouldBreak)); + text ("{shouldBreak: " ^ (string_of_bool shouldBreak) ^ "}"); concat [text ","; line]; toDoc doc; ] @@ -416599,7 +416646,7 @@ val filterParsingAttrs : Parsetree.attributes -> Parsetree.attributes val isBracedExpr : Parsetree.expression -> bool -val isPipeExpr : Parsetree.expression -> bool +val isSinglePipeExpr : Parsetree.expression -> bool val extractValueDescriptionFromModExpr: Parsetree.module_expr -> Parsetree.value_description list @@ -416793,15 +416840,33 @@ let isBracedExpr expr = | (Some _, _) -> true | _ -> false +let isMultilineText txt = + let len = String.length txt in + let rec check i= + if i >= len then false + else + let c = String.unsafe_get txt i in + match c with + | '\010' | '\013' -> true + | '\\' -> + if (i + 2) = len then false + else + check (i + 2) + | _ -> check (i + 1) + in + check 0 + let isHuggableExpression expr = match expr.pexp_desc with | Pexp_array _ | Pexp_tuple _ + | Pexp_constant (Pconst_string (_, Some _)) | Pexp_construct ({txt = Longident.Lident ("::" | "[]")}, _) | Pexp_extension ({txt = "bs.obj"}, _) | Pexp_record _ -> true | _ when isBlockExpr expr -> true | _ when isBracedExpr expr -> true + | Pexp_constant (Pconst_string (txt, None)) when isMultilineText txt -> true | _ -> false let isHuggableRhs expr = @@ -416819,6 +416884,7 @@ let isHuggablePattern pattern = | Ppat_array _ | Ppat_tuple _ | Ppat_record _ + | Ppat_variant _ | Ppat_construct _ -> true | _ -> false @@ -416844,6 +416910,7 @@ let isUnaryExpression expr = match expr.pexp_desc with ) when isUnaryOperator operator -> true | _ -> false +(* TODO: tweak this to check for ghost ^ as template literal *) let isBinaryOperator operator = match operator with | ":=" | "||" @@ -416857,9 +416924,11 @@ let isBinaryOperator operator = match operator with let isBinaryExpression expr = match expr.pexp_desc with | Pexp_apply( - {pexp_desc = Pexp_ident {txt = Longident.Lident operator}}, + {pexp_desc = Pexp_ident {txt = Longident.Lident operator; loc = operatorLoc}}, [(Nolabel, _operand1); (Nolabel, _operand2)] - ) when isBinaryOperator operator -> true + ) when isBinaryOperator operator && + not (operatorLoc.loc_ghost && operator = "^") (* template literal *) + -> true | _ -> false let isEqualityOperator operator = match operator with @@ -417007,9 +417076,14 @@ let isJsxExpression expr = loop expr.Parsetree.pexp_attributes | _ -> false -let hasJsxAttribute attributes = match attributes with - | ({Location.txt = "JSX"},_)::_ -> true - | _ -> false +let hasJsxAttribute attributes = + let rec loop attrs = + match attrs with + | [] -> false + | ({Location.txt = "JSX"}, _)::_ -> true + | _::attrs -> loop attrs + in + loop attributes let shouldIndentBinaryExpr expr = let samePrecedenceSubExpression operator subExpression = @@ -417111,18 +417185,17 @@ let rec collectPatternsFromListConstruct acc pattern = collectPatternsFromListConstruct (pat::acc) rest | _ -> List.rev acc, pattern -let rec isTemplateLiteral expr = - let isPexpConstantString expr = match expr.pexp_desc with - | Pexp_constant (Pconst_string (_, Some _)) -> true - | _ -> false - in +(* Simple heuristic to detect template literal sugar: + * `${user.name} lastName` parses internally as user.name ++ ` lastName`. + * The thing is: the ++ operator (parsed as `^`) will always have a ghost loc. + * A ghost loc is only produced by our parser. + * Hence, if we have that ghost operator, we know for sure it's a template literal. *) +let isTemplateLiteral expr = match expr.pexp_desc with | Pexp_apply ( - {pexp_desc = Pexp_ident {txt = Longident.Lident "^"}}, - [Nolabel, arg1; Nolabel, arg2] - ) when not (isPexpConstantString arg1 && isPexpConstantString arg2) -> - isTemplateLiteral arg1 || isTemplateLiteral arg2 - | Pexp_constant (Pconst_string (_, Some _)) -> true + {pexp_desc = Pexp_ident {txt = Longident.Lident "^"; loc}}, + [Nolabel, _; Nolabel, _] + ) when loc.loc_ghost -> true | _ -> false (* Blue | Red | Green -> [Blue; Red; Green] *) @@ -417134,11 +417207,11 @@ let collectOrPatternChain pat = in loop pat [] -let isPipeExpr expr = match expr.pexp_desc with +let rec isSinglePipeExpr expr = match expr.pexp_desc with | Pexp_apply( {pexp_desc = Pexp_ident {txt = Longident.Lident ("|." | "|>") }}, - [(Nolabel, _operand1); (Nolabel, _operand2)] - ) -> true + [(Nolabel, operand1); (Nolabel, _operand2)] + ) when not (isSinglePipeExpr operand1) -> true | _ -> false let extractValueDescriptionFromModExpr modExpr = @@ -417211,6 +417284,12 @@ let make () = { trailing = Hashtbl.create 100; } +let copy tbl = { + leading = Hashtbl.copy tbl.leading; + inside = Hashtbl.copy tbl.inside; + trailing = Hashtbl.copy tbl.trailing; +} + let empty = make () let log t = @@ -417939,10 +418018,31 @@ let rec walkStructure s t comments = {vb with pvb_pat = {vb.pvb_pat with ppat_loc = {pat.ppat_loc with loc_end = t.ptyp_loc.loc_end}}} + + | ({ppat_desc = Ppat_constraint (pat, ({ptyp_desc = Ptyp_poly (_::_, t)} as typ))} as constrainedPattern), + {pexp_desc = Pexp_newtype (_, {pexp_desc = Pexp_constraint (expr, _)})} -> + (* + * The location of the Ptyp_poly on the pattern is the whole thing. + * let x: + * type t. (int, int) => int = + * (a, b) => { + * // comment + * a + b + * } + *) + {vb with + pvb_pat = { + constrainedPattern with + ppat_desc = Ppat_constraint (pat, typ); + ppat_loc = {constrainedPattern.ppat_loc with loc_end = t.ptyp_loc.loc_end}; + }; + pvb_expr = expr + } | _ -> vb in let patternLoc = vb.Parsetree.pvb_pat.ppat_loc in let exprLoc = vb.Parsetree.pvb_expr.pexp_loc in + let expr = vb.pvb_expr in let (leading, inside, trailing) = partitionByLoc comments patternLoc in @@ -417951,21 +418051,19 @@ let rec walkStructure s t comments = * let |* before *| a = 1 *) attach t.leading patternLoc leading; walkPattern vb.Parsetree.pvb_pat t inside; - (* let pattern = expr -> pattern and expr on the same line *) - (* if patternLoc.loc_end.pos_lnum == exprLoc.loc_start.pos_lnum then ( *) - let (afterPat, surroundingExpr) = - partitionAdjacentTrailing patternLoc trailing - in - attach t.trailing patternLoc afterPat; - let (beforeExpr, insideExpr, afterExpr) = - partitionByLoc surroundingExpr exprLoc in - if isBlockExpr vb.pvb_expr then ( - walkExpr vb.pvb_expr t (List.concat [beforeExpr; insideExpr; afterExpr]) - ) else ( - attach t.leading exprLoc beforeExpr; - walkExpr vb.Parsetree.pvb_expr t insideExpr; - attach t.trailing exprLoc afterExpr - ) + let (afterPat, surroundingExpr) = + partitionAdjacentTrailing patternLoc trailing + in + attach t.trailing patternLoc afterPat; + let (beforeExpr, insideExpr, afterExpr) = + partitionByLoc surroundingExpr exprLoc in + if isBlockExpr expr then ( + walkExpr expr t (List.concat [beforeExpr; insideExpr; afterExpr]) + ) else ( + attach t.leading exprLoc beforeExpr; + walkExpr expr t insideExpr; + attach t.trailing exprLoc afterExpr + ) and walkExpr expr t comments = let open Location in @@ -418452,13 +418550,12 @@ let rec walkStructure s t comments = attach t.trailing callExpr.pexp_loc afterExpr; walkList ~getLoc:(fun (_argLabel, expr) -> - let loc = match expr.Parsetree.pexp_attributes with + match expr.Parsetree.pexp_attributes with | ({Location.txt = "ns.namedArgLoc"; loc}, _)::_attrs -> {loc with loc_end = expr.pexp_loc.loc_end} | _ -> expr.pexp_loc - in - loc) + ) ~walkNode:walkExprArgument arguments t @@ -419013,7 +419110,13 @@ and walkExprArgument (_argLabel, expr) t comments = and walkTypeParameters typeParameters t comments = visitListButContinueWithRemainingComments - ~getLoc:(fun (_, _, typexpr) -> typexpr.Parsetree.ptyp_loc) + ~getLoc:(fun (_, _, typexpr) -> + match typexpr.Parsetree.ptyp_attributes with + | ({Location.txt = "ns.namedArgLoc"; loc}, _)::_attrs -> + {loc with loc_end = typexpr.ptyp_loc.loc_end} + | _ -> + typexpr.ptyp_loc + ) ~walkNode:walkTypeParameter ~newlineDelimited:false typeParameters @@ -421292,6 +421395,8 @@ val includeModExpr : Parsetree.module_expr -> bool val arrowReturnTypExpr: Parsetree.core_type -> bool +val patternRecordRowRhs: Parsetree.pattern -> bool + end = struct #1 "res_parens.ml" module ParsetreeViewer = Res_parsetree_viewer @@ -421438,9 +421543,10 @@ type kind = Parenthesized | Braced of Location.t | Nothing match rhs.Parsetree.pexp_desc with | Parsetree.Pexp_apply( {pexp_attributes = []; - pexp_desc = Pexp_ident {txt = Longident.Lident operator}}, + pexp_desc = Pexp_ident {txt = Longident.Lident operator; loc = operatorLoc}}, [_, _left; _, _right] - ) when ParsetreeViewer.isBinaryOperator operator -> + ) when ParsetreeViewer.isBinaryOperator operator && + not (operatorLoc.loc_ghost && operator = "^") -> let precParent = ParsetreeViewer.operatorPrecedence parentOperator in let precChild = ParsetreeViewer.operatorPrecedence operator in precParent == precChild @@ -421449,9 +421555,10 @@ type kind = Parenthesized | Braced of Location.t | Nothing let flattenOperandRhs parentOperator rhs = match rhs.Parsetree.pexp_desc with | Parsetree.Pexp_apply( - {pexp_desc = Pexp_ident {txt = Longident.Lident operator}}, + {pexp_desc = Pexp_ident {txt = Longident.Lident operator; loc = operatorLoc}}, [_, _left; _, _right] - ) when ParsetreeViewer.isBinaryOperator operator -> + ) when ParsetreeViewer.isBinaryOperator operator && + not (operatorLoc.loc_ghost && operator = "^") -> let precParent = ParsetreeViewer.operatorPrecedence parentOperator in let precChild = ParsetreeViewer.operatorPrecedence operator in precParent >= precChild || rhs.pexp_attributes <> [] @@ -421703,6 +421810,12 @@ let arrowReturnTypExpr typExpr = match typExpr.Parsetree.ptyp_desc with | Parsetree.Ptyp_arrow _ -> true | _ -> false +let patternRecordRowRhs (pattern : Parsetree.pattern) = + match pattern.ppat_desc with + | Ppat_constraint ({ppat_desc = Ppat_unpack _}, {ptyp_desc = Ptyp_package _}) -> false + | Ppat_constraint _ -> true + | _ -> false + end module Res_printer : sig #1 "res_printer.mli" @@ -421734,6 +421847,17 @@ module Token = Res_token module Parens = Res_parens module ParsetreeViewer = Res_parsetree_viewer +type callbackStyle = + (* regular arrow function, example: `let f = x => x + 1` *) + | NoCallback + (* `Thing.map(foo, (arg1, arg2) => MyModuleBlah.toList(argument))` *) + | FitsOnOneLine + (* Thing.map(longArgumet, veryLooooongArgument, (arg1, arg2) => + * MyModuleBlah.toList(argument) + * ) + *) + | ArgumentsFitOnOneLine + let addParens doc = Doc.group ( Doc.concat [ @@ -422116,6 +422240,10 @@ let printStringLoc sloc cmtTbl = let doc = printIdentLike sloc.Location.txt in printComments doc cmtTbl sloc.loc +let printStringContents txt = + let lines = String.split_on_char '\n' txt in + Doc.join ~sep:Doc.literalLine (List.map Doc.text lines) + let printConstant c = match c with | Parsetree.Pconst_integer (s, suffix) -> begin match suffix with @@ -422123,11 +422251,17 @@ let printConstant c = match c with | None -> Doc.text s end | Pconst_string (txt, None) -> - Doc.text ("\"" ^ txt ^ "\"") + Doc.concat [ + Doc.text "\""; + printStringContents txt; + Doc.text "\""; + ] | Pconst_string (txt, Some prefix) -> Doc.concat [ if prefix = "js" then Doc.nil else Doc.text prefix; - Doc.text ("`" ^ txt ^ "`") + Doc.text "`"; + printStringContents txt; + Doc.text "`"; ] | Pconst_float (s, _) -> Doc.text s | Pconst_char c -> Doc.text ("'" ^ (Char.escaped c) ^ "'") @@ -423280,7 +423414,7 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = let typDoc = let doc = printTypExpr n cmtTbl in match n.ptyp_desc with - | Ptyp_arrow _ | Ptyp_tuple _ -> addParens doc + | Ptyp_arrow _ | Ptyp_tuple _ | Ptyp_alias _ -> addParens doc | _ -> doc in Doc.group ( @@ -423320,7 +423454,9 @@ and printTypExpr (typExpr : Parsetree.core_type) cmtTbl = Doc.softLine; if isUncurried then Doc.concat [Doc.dot; Doc.space] else Doc.nil; Doc.join ~sep:(Doc.concat [Doc.comma; Doc.line]) ( - List.map (fun tp -> printTypeParameter tp cmtTbl) args + List.map (fun tp -> + printTypeParameter tp cmtTbl + ) args ) ] ); @@ -423520,6 +423656,11 @@ and printTypeParameter (attrs, lbl, typ) cmtTbl = | Labelled _ -> Doc.nil | Optional _lbl -> Doc.text "=?" in + let (loc, typ) = match typ.ptyp_attributes with + | ({Location.txt = "ns.namedArgLoc"; loc}, _)::attrs -> + ({loc with loc_end = typ.ptyp_loc.loc_end}, {typ with ptyp_attributes = attrs}) + | _ -> (typ.ptyp_loc, typ) + in let doc = Doc.group ( Doc.concat [ uncurried; @@ -423529,7 +423670,7 @@ and printTypeParameter (attrs, lbl, typ) cmtTbl = optionalIndicator; ] ) in - printComments doc cmtTbl typ.ptyp_loc + printComments doc cmtTbl loc and printValueBinding ~recFlag vb cmtTbl i = let (hasGenType, attrs) = ParsetreeViewer.splitGenTypeAttr vb.pvb_attributes in @@ -423620,13 +423761,26 @@ and printValueBinding ~recFlag vb cmtTbl i = | Braced braces -> printBraces doc expr braces | Nothing -> doc in - if ParsetreeViewer.isPipeExpr vb.pvb_expr then + let patternDoc = printPattern vb.pvb_pat cmtTbl in + (* + * we want to optimize the layout of one pipe: + * let tbl = data->Js.Array2.reduce((map, curr) => { + * ... + * }) + * important is that we don't do this for multiple pipes: + * let decoratorTags = + * items + * ->Js.Array2.filter(items => {items.category === Decorators}) + * ->Belt.Array.map(...) + * Multiple pipes chained together lend themselves more towards the last layout. + *) + if ParsetreeViewer.isSinglePipeExpr vb.pvb_expr then Doc.customLayout [ Doc.group ( Doc.concat [ attrs; header; - printPattern vb.pvb_pat cmtTbl; + patternDoc; Doc.text " ="; Doc.space; printedExpr; @@ -423636,7 +423790,7 @@ and printValueBinding ~recFlag vb cmtTbl i = Doc.concat [ attrs; header; - printPattern vb.pvb_pat cmtTbl; + patternDoc; Doc.text " ="; Doc.indent ( Doc.concat [ @@ -423669,7 +423823,7 @@ and printValueBinding ~recFlag vb cmtTbl i = Doc.concat [ attrs; header; - printPattern vb.pvb_pat cmtTbl; + patternDoc; Doc.text " ="; if shouldIndent then Doc.indent ( @@ -424111,16 +424265,27 @@ and printPatternRecordRow row cmtTbl = longident.loc with loc_end = pattern.Parsetree.ppat_loc.loc_end } in + let rhsDoc = + let doc = printPattern pattern cmtTbl in + if Parens.patternRecordRowRhs pattern then + addParens doc + else + doc + in let doc = Doc.group ( Doc.concat([ printLidentPath longident cmtTbl; - Doc.text ": "; - Doc.indent( - Doc.concat [ - Doc.softLine; - printPattern pattern cmtTbl; - ] - ) + Doc.text ":"; + (if ParsetreeViewer.isHuggablePattern pattern then + Doc.concat [Doc.space; rhsDoc] + else + Doc.indent( + Doc.concat [ + Doc.line; + rhsDoc; + ] + ) + ); ]) ) in printComments doc cmtTbl locForComments @@ -424715,7 +424880,7 @@ and printExpression (e : Parsetree.expression) cmtTbl = in let hasConstraint = match typConstraint with | Some _ -> true | None -> false in let parametersDoc = printExprFunParameters - ~inCallback:false + ~inCallback:NoCallback ~uncurried ~hasConstraint parameters @@ -424920,7 +425085,9 @@ and printPexpFun ~inCallback e cmtTbl = returnDoc; ] ); - if inCallback then Doc.softLine else Doc.nil; + (match inCallback with + | FitsOnOneLine | ArgumentsFitOnOneLine -> Doc.softLine + | _ -> Doc.nil); ] else Doc.concat [ @@ -424936,15 +425103,13 @@ and printPexpFun ~inCallback e cmtTbl = ] | _ -> Doc.nil in - Doc.group ( - Doc.concat [ - printAttributes attrs cmtTbl; - parametersDoc; - typConstraintDoc; - Doc.text " =>"; - returnExprDoc; - ] - ) + Doc.concat [ + printAttributes attrs cmtTbl; + parametersDoc; + typConstraintDoc; + Doc.text " =>"; + returnExprDoc; + ] and printTernaryOperand expr cmtTbl = let doc = printExpressionWithComments expr cmtTbl in @@ -425007,10 +425172,16 @@ and printTemplateLiteral expr cmtTbl = Doc.concat [lhs; rhs] | Pexp_constant (Pconst_string (txt, Some prefix)) -> tag := prefix; - Doc.text txt + printStringContents txt | _ -> let doc = printExpressionWithComments expr cmtTbl in - Doc.concat [Doc.text "${"; doc; Doc.rbrace] + Doc.group ( + Doc.concat [ + Doc.text "${"; + Doc.indent doc; + Doc.rbrace; + ] + ) in let content = walkExpr expr in Doc.concat [ @@ -425136,6 +425307,12 @@ and printBinaryExpression (expr : Parsetree.expression) cmtTbl = end else begin match expr.pexp_desc with + | Pexp_apply ( + {pexp_desc = Pexp_ident {txt = Longident.Lident "^"; loc}}, + [Nolabel, _; Nolabel, _] + ) when loc.loc_ghost -> + let doc = printTemplateLiteral expr cmtTbl in + printComments doc cmtTbl expr.Parsetree.pexp_loc | Pexp_setfield (lhs, field, rhs) -> let doc = printSetFieldExpr expr.pexp_attributes lhs field rhs expr.pexp_loc cmtTbl in if isLhs then addParens doc else doc @@ -425459,7 +425636,25 @@ and printPexpApply expr cmtTbl = let argsDoc = printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl in + (* + * Fixes the following layout (the `[` and `]` should break): + * [fn(x => { + * let _ = x + * }), fn(y => { + * let _ = y + * }), fn(z => { + * let _ = z + * })] + * See `Doc.willBreak documentation in interface file for more context. + * Context: + * https://github.com/rescript-lang/syntax/issues/111 + * https://github.com/rescript-lang/syntax/issues/166 + *) + let maybeBreakParent = + if Doc.willBreak argsDoc then Doc.breakParent else Doc.nil + in Doc.concat [ + maybeBreakParent; printAttributes attrs cmtTbl; callExprDoc; argsDoc; @@ -425657,6 +425852,10 @@ and printJsxName {txt = lident} = Doc.join ~sep:Doc.dot (List.map Doc.text segments) and printArgumentsWithCallbackInFirstPosition ~uncurried args cmtTbl = + (* Because the same subtree gets printed twice, we need to copy the cmtTbl. + * consumed comments need to be marked not-consumed and reprinted… + * Cheng's different comment algorithm will solve this. *) + let cmtTblCopy = CommentTable.copy cmtTbl in let (callback, printedArgs) = match args with | (lbl, expr)::args -> let lblDoc = match lbl with @@ -425672,11 +425871,12 @@ and printArgumentsWithCallbackInFirstPosition ~uncurried args cmtTbl = in let callback = Doc.concat [ lblDoc; - printPexpFun ~inCallback:true expr cmtTbl + printPexpFun ~inCallback:FitsOnOneLine expr cmtTbl ] in - let printedArgs = List.map (fun arg -> - printArgument arg cmtTbl - ) args |> Doc.join ~sep:(Doc.concat [Doc.comma; Doc.line]) + let printedArgs = + Doc.join ~sep:(Doc.concat [Doc.comma; Doc.line]) ( + List.map (fun arg -> printArgument arg cmtTbl) args + ) in (callback, printedArgs) | _ -> assert false @@ -425702,15 +425902,20 @@ and printArgumentsWithCallbackInFirstPosition ~uncurried args cmtTbl = * arg3, * ) *) - let breakAllArgs = printArguments ~uncurried args cmtTbl in + let breakAllArgs = printArguments ~uncurried args cmtTblCopy in Doc.customLayout [ fitsOnOneLine; breakAllArgs; ] and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl = + (* Because the same subtree gets printed twice, we need to copy the cmtTbl. + * consumed comments need to be marked not-consumed and reprinted… + * Cheng's different comment algorithm will solve this. *) + let cmtTblCopy = CommentTable.copy cmtTbl in + let cmtTblCopy2 = CommentTable.copy cmtTbl in let rec loop acc args = match args with - | [] -> (Doc.nil, Doc.nil) + | [] -> (Doc.nil, Doc.nil, Doc.nil) | [lbl, expr] -> let lblDoc = match lbl with | Asttypes.Nolabel -> Doc.nil @@ -425723,13 +425928,20 @@ and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl = Doc.tilde; printIdentLike txt; Doc.equal; Doc.question; ] in - let callback = printPexpFun ~inCallback:true expr cmtTbl in - (Doc.concat (List.rev acc), Doc.concat [lblDoc; callback]) + let callbackFitsOnOneLine = + printPexpFun ~inCallback:FitsOnOneLine expr cmtTbl in + let callbackArgumetnsFitsOnOneLine = + printPexpFun ~inCallback:ArgumentsFitOnOneLine expr cmtTblCopy in + ( + Doc.concat (List.rev acc), + Doc.concat [lblDoc; callbackFitsOnOneLine], + Doc.concat [lblDoc; callbackArgumetnsFitsOnOneLine] + ) | arg::args -> let argDoc = printArgument arg cmtTbl in loop (Doc.line::Doc.comma::argDoc::acc) args in - let (printedArgs, callback) = loop [] args in + let (printedArgs, callback, callback2) = loop [] args in (* Thing.map(foo, (arg1, arg2) => MyModuleBlah.toList(argument)) *) let fitsOnOneLine = Doc.concat [ @@ -425746,10 +425958,8 @@ and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl = let arugmentsFitOnOneLine = Doc.concat [ if uncurried then Doc.text "(." else Doc.lparen; - Doc.softLine; printedArgs; - Doc.breakableGroup ~forceBreak:true callback; - Doc.softLine; + Doc.breakableGroup ~forceBreak:true callback2; Doc.rparen; ] in @@ -425761,7 +425971,7 @@ and printArgumentsWithCallbackInLastPosition ~uncurried args cmtTbl = * (param1, parm2) => doStuff(param1, parm2) * ) *) - let breakAllArgs = printArguments ~uncurried args cmtTbl in + let breakAllArgs = printArguments ~uncurried args cmtTblCopy2 in Doc.customLayout [ fitsOnOneLine; arugmentsFitOnOneLine; @@ -426020,11 +426230,20 @@ and printExprFunParameters ~inCallback ~uncurried ~hasConstraint parameters cmtT Doc.text "()" (* let f = (~greeting, ~from as hometown, ~x=?) => () *) | parameters -> + let inCallback = match inCallback with + | FitsOnOneLine -> true + | _ -> false + in let lparen = if uncurried then Doc.text "(. " else Doc.lparen in let shouldHug = ParsetreeViewer.parametersShouldHug parameters in let printedParamaters = Doc.concat [ if shouldHug || inCallback then Doc.nil else Doc.softLine; - Doc.join ~sep:(Doc.concat [Doc.comma; if inCallback then Doc.space else Doc.line]) + Doc.join + ~sep:( + Doc.concat [ + Doc.comma; if inCallback then Doc.line else Doc.line + ] + ) (List.map (fun p -> printExpFunParameter p cmtTbl) parameters) ] in Doc.group ( @@ -426356,18 +426575,27 @@ and printPayload (payload : Parsetree.payload) cmtTbl = | PStr [{pstr_desc = Pstr_eval (expr, attrs)}] -> let exprDoc = printExpressionWithComments expr cmtTbl in let needsParens = match attrs with | [] -> false | _ -> true in - Doc.concat [ - Doc.lparen; - Doc.indent ( - Doc.concat [ - Doc.softLine; - printAttributes attrs cmtTbl; - if needsParens then addParens exprDoc else exprDoc; - ] - ); - Doc.softLine; - Doc.rparen; - ] + let shouldHug = ParsetreeViewer.isHuggableExpression expr in + if shouldHug then + Doc.concat [ + Doc.lparen; + printAttributes attrs cmtTbl; + if needsParens then addParens exprDoc else exprDoc; + Doc.rparen; + ] + else + Doc.concat [ + Doc.lparen; + Doc.indent ( + Doc.concat [ + Doc.softLine; + printAttributes attrs cmtTbl; + if needsParens then addParens exprDoc else exprDoc; + ] + ); + Doc.softLine; + Doc.rparen; + ] | PStr [{pstr_desc = Pstr_value (_recFlag, _bindings)} as si] -> addParens(printStructureItem si cmtTbl) | PStr structure -> @@ -426634,7 +426862,7 @@ and printModFunctorParam (attrs, lbl, optModType) cmtTbl = in let attrs = printAttributes attrs cmtTbl in let lblDoc = - let doc = Doc.text lbl.txt in + let doc = if lbl.txt = "*" then Doc.text "()" else Doc.text lbl.txt in printComments doc cmtTbl lbl.loc in let doc = Doc.group ( @@ -428646,9 +428874,11 @@ and parseBracketAccess p expr startPos = let stringStart = p.startPos in match p.Parser.token with | String s -> + let s = if p.mode = ParseForTypeChecker then parseStringLiteral s else s in Parser.next p; let stringEnd = p.prevEndPos in Parser.expect Rbracket p; + Parser.eatBreadcrumb p; let rbracket = p.prevEndPos in let e = let identLoc = mkLoc stringStart stringEnd in @@ -428674,6 +428904,7 @@ and parseBracketAccess p expr startPos = | _ -> let accessExpr = parseConstrainedOrCoercedExpr p in Parser.expect Rbracket p; + Parser.eatBreadcrumb p; let rbracket = p.prevEndPos in let arrayLoc = mkLoc lbracket rbracket in begin match p.token with @@ -428704,7 +428935,6 @@ and parseBracketAccess p expr startPos = ) [Nolabel, expr; Nolabel, accessExpr] in - Parser.eatBreadcrumb p; parsePrimaryExpr ~operand:e p end @@ -429428,6 +429658,7 @@ and parseBracedOrRecordExpr p = Parser.expect Rbrace p; expr | String s -> + let s = if p.mode = ParseForTypeChecker then parseStringLiteral s else s in let field = let loc = mkLoc p.startPos p.endPos in Parser.next p; @@ -430588,9 +430819,13 @@ and parseTypeParameter p = match p.Parser.token with | Tilde -> Parser.next p; - let (name, _loc) = parseLident p in + let (name, loc) = parseLident p in + let lblLocAttr = (Location.mkloc "ns.namedArgLoc" loc, Parsetree.PStr []) in Parser.expect ~grammar:Grammar.TypeExpression Colon p; - let typ = parseTypExpr p in + let typ = + let typ = parseTypExpr p in + {typ with ptyp_attributes = lblLocAttr::typ.ptyp_attributes} + in begin match p.Parser.token with | Equal -> Parser.next p; @@ -430659,9 +430894,13 @@ and parseEs6ArrowType ~attrs p = match p.Parser.token with | Tilde -> Parser.next p; - let (name, _loc) = parseLident p in + let (name, loc) = parseLident p in + let lblLocAttr = (Location.mkloc "ns.namedArgLoc" loc, Parsetree.PStr []) in Parser.expect ~grammar:Grammar.TypeExpression Colon p; - let typ = parseTypExpr ~alias:false ~es6Arrow:false p in + let typ = + let typ = parseTypExpr ~alias:false ~es6Arrow:false p in + {typ with ptyp_attributes = lblLocAttr::typ.ptyp_attributes} + in let arg = match p.Parser.token with | Equal -> Parser.next p; @@ -430672,7 +430911,8 @@ and parseEs6ArrowType ~attrs p = in Parser.expect EqualGreater p; let returnType = parseTypExpr ~alias:false p in - Ast_helper.Typ.arrow ~attrs arg typ returnType + let loc = mkLoc startPos p.prevEndPos in + Ast_helper.Typ.arrow ~loc ~attrs arg typ returnType | _ -> let parameters = parseTypeParameters p in Parser.expect EqualGreater p; @@ -431810,6 +432050,10 @@ and parseConstrDef ~parseAttrs p = Parser.next p; let longident = parseModuleLongIdent ~lowercase:false p in Parsetree.Pext_rebind longident + | Colon -> + Parser.next p; + let typ = parseTypExpr p in + Parsetree.Pext_decl (Pcstr_tuple [], Some typ) | _ -> Parsetree.Pext_decl (Pcstr_tuple [], None) in @@ -432158,6 +432402,11 @@ and parseFunctorArg p = Parser.expect Colon p; let moduleType = parseModuleType p in Some (attrs, argName, Some moduleType, startPos) + | Lparen -> + Parser.next p; + Parser.expect Rparen p; + let argName = Location.mkloc "*" (mkLoc startPos p.prevEndPos) in + Some (attrs, argName, None, startPos) | _ -> None diff --git a/linux/ninja.exe b/linux/ninja.exe index af29b9ad74..01b9d01a21 100755 Binary files a/linux/ninja.exe and b/linux/ninja.exe differ diff --git a/package.json b/package.json index 57c6cb8ade..8c1c02fd2d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "coverage": "nyc --timeout=3000 --reporter=html mocha jscomp/test/*test.js && open ./coverage/index.html" }, "name": "bs-platform", - "version": "8.4.0-dev.1", + "version": "8.4.0", "description": "ReScript compiler, OCaml standard libary by ReScript and its required runtime support", "repository": { "type": "git", diff --git a/syntax b/syntax index 7f5c968088..7cc70c947c 160000 --- a/syntax +++ b/syntax @@ -1 +1 @@ -Subproject commit 7f5c9680883f4e5b7c9958e77b954d5637e651d8 +Subproject commit 7cc70c947c35357f71e24920c0e0c4cb58493125 diff --git a/win32/ninja.exe b/win32/ninja.exe index 5d23c62a63..a402ee855b 100644 Binary files a/win32/ninja.exe and b/win32/ninja.exe differ