diff --git a/analysis/vendor/ext/config.ml b/analysis/vendor/ext/config.ml index 2b181a608..35040eaa5 100644 --- a/analysis/vendor/ext/config.ml +++ b/analysis/vendor/ext/config.ml @@ -13,7 +13,8 @@ let bs_only = ref true let unsafe_empty_array = ref false -let use_automatic_curried_application = ref false +type uncurried = Legacy | Uncurried | Swap +let uncurried = ref Legacy and cmi_magic_number = "Caml1999I022" diff --git a/analysis/vendor/ext/config.mli b/analysis/vendor/ext/config.mli index 3c3a78fd6..d409fe0b6 100644 --- a/analysis/vendor/ext/config.mli +++ b/analysis/vendor/ext/config.mli @@ -47,4 +47,5 @@ val cmt_magic_number : string val print_config : out_channel -> unit -val use_automatic_curried_application : bool ref \ No newline at end of file +type uncurried = Legacy | Uncurried | Swap +val uncurried : uncurried ref \ No newline at end of file diff --git a/analysis/vendor/ml/ctype.ml b/analysis/vendor/ml/ctype.ml index c74fa9f57..62745e025 100644 --- a/analysis/vendor/ml/ctype.ml +++ b/analysis/vendor/ml/ctype.ml @@ -2341,9 +2341,6 @@ let rec unify (env:Env.t ref) t1 t2 = with Cannot_expand -> unify2 env t1 t2 end - | (Tconstr (Pident {name="function$"}, [tFun; _], _), Tarrow _) when !Config.use_automatic_curried_application -> - (* subtype: an uncurried function is cast to a curried one *) - unify2 env tFun t2 | _ -> unify2 env t1 t2 end; @@ -2399,6 +2396,9 @@ and unify3 env t1 t1' t2 t2' = link_type t2' t1; | (Tfield _, Tfield _) -> (* special case for GADTs *) unify_fields env t1' t2' + | (Tconstr (Pident {name="function$"}, [tFun; _], _), Tarrow _) when !Config.uncurried = Uncurried -> + (* subtype: an uncurried function is cast to a curried one *) + unify2 env tFun t2 | _ -> begin match !umode with | Expression -> @@ -3951,7 +3951,33 @@ let rec subtype_rec env trace t1 t2 cstrs = end | (Tconstr(p1, _, _), _) when generic_private_abbrev env p1 -> subtype_rec env trace (expand_abbrev_opt env t1) t2 cstrs -(* | (_, Tconstr(p2, _, _)) when generic_private_abbrev false env p2 -> + | (Tconstr(_, [], _), Tconstr(_, [], _)) -> (* type coercion for records *) + (match extract_concrete_typedecl env t1, extract_concrete_typedecl env t2 with + | (_, _, {type_kind=Type_record (fields1, repr1)}), (_, _, {type_kind=Type_record (fields2, repr2)}) -> + let field_is_optional id repr = match repr with + | Record_optional_labels lbls -> List.mem (Ident.name id) lbls + | _ -> false in + let violation = ref false in + let label_decl_sub (acc1, acc2) ld2 = + match fields1 |> List.find_opt (fun ld1 -> Ident.name ld1.ld_id = Ident.name ld2.ld_id) with + | Some ld1 -> + if field_is_optional ld1.ld_id repr1 && not (field_is_optional ld2.ld_id repr2) then + (* optional field can't be cast to non-optional one *) + violation := true; + ld1.ld_type :: acc1, ld2.ld_type :: acc2 + | None -> + (* field must be present *) + violation := true; + (acc1, acc2) in + let tl1, tl2 = List.fold_left label_decl_sub ([], []) fields2 in + if !violation + then (trace, t1, t2, !univar_pairs)::cstrs + else + subtype_list env trace tl1 tl2 cstrs + | _ -> (trace, t1, t2, !univar_pairs)::cstrs + | exception Not_found -> (trace, t1, t2, !univar_pairs)::cstrs + ) + (* | (_, Tconstr(p2, _, _)) when generic_private_abbrev false env p2 -> subtype_rec env trace t1 (expand_abbrev_opt env t2) cstrs *) | (Tobject (f1, _), Tobject (f2, _)) when is_Tvar (object_row f1) && is_Tvar (object_row f2) -> diff --git a/analysis/vendor/ml/typecore.ml b/analysis/vendor/ml/typecore.ml index c0cd6e131..e9aea7c5f 100644 --- a/analysis/vendor/ml/typecore.ml +++ b/analysis/vendor/ml/typecore.ml @@ -2980,7 +2980,7 @@ and type_argument ?recarg env sarg ty_expected' ty_expected = texp and is_automatic_curried_application env funct = (* When a curried function is used with uncurried application, treat it as a curried application *) - !Config.use_automatic_curried_application && + !Config.uncurried = Uncurried && match (expand_head env funct.exp_type).desc with | Tarrow _ -> true | _ -> false diff --git a/analysis/vendor/res_syntax/reactjs_jsx_v3.ml b/analysis/vendor/res_syntax/reactjs_jsx_v3.ml index d24b3a2d2..b1ca0e281 100644 --- a/analysis/vendor/res_syntax/reactjs_jsx_v3.ml +++ b/analysis/vendor/res_syntax/reactjs_jsx_v3.ml @@ -597,6 +597,7 @@ let jsxMapper ~config = match List.filter React_jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> + let pval_type = React_jsx_common.extractUncurried pval_type in let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = match ptyp_desc with | Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest)) @@ -648,6 +649,7 @@ let jsxMapper ~config = let emptyLoc = Location.in_file fileName in let mapBinding binding = if React_jsx_common.hasAttrOnBinding binding then + let binding = React_jsx_common.removeArity binding in let bindingLoc = binding.pvb_loc in let bindingPatLoc = binding.pvb_pat.ppat_loc in let binding = @@ -957,6 +959,13 @@ let jsxMapper ~config = } innerExpressionWithRef in + let fullExpression = + if !Config.uncurried = Uncurried then + fullExpression + |> Ast_uncurried.uncurriedFun ~loc:fullExpression.pexp_loc + ~arity:1 + else fullExpression + in let fullExpression = match fullModuleName with | "" -> fullExpression @@ -1031,6 +1040,7 @@ let jsxMapper ~config = match List.filter React_jsx_common.hasAttr pval_attributes with | [] -> [item] | [_] -> + let pval_type = React_jsx_common.extractUncurried pval_type in let rec getPropTypes types ({ptyp_loc; ptyp_desc} as fullType) = match ptyp_desc with | Ptyp_arrow (name, type_, ({ptyp_desc = Ptyp_arrow _} as rest)) diff --git a/analysis/vendor/res_syntax/reactjs_jsx_v4.ml b/analysis/vendor/res_syntax/reactjs_jsx_v4.ml index e2afe36d6..9f7f1b5bc 100644 --- a/analysis/vendor/res_syntax/reactjs_jsx_v4.ml +++ b/analysis/vendor/res_syntax/reactjs_jsx_v4.ml @@ -952,6 +952,12 @@ let mapBinding ~config ~emptyLoc ~pstr_loc ~fileName ~recFlag binding = innerExpression else innerExpression) in + let fullExpression = + if !Config.uncurried = Uncurried then + fullExpression + |> Ast_uncurried.uncurriedFun ~loc:fullExpression.pexp_loc ~arity:1 + else fullExpression + in let fullExpression = match fullModuleName with | "" -> fullExpression diff --git a/analysis/vendor/res_syntax/res_core.ml b/analysis/vendor/res_syntax/res_core.ml index 1e728ccaa..bc2e29c81 100644 --- a/analysis/vendor/res_syntax/res_core.ml +++ b/analysis/vendor/res_syntax/res_core.ml @@ -146,9 +146,6 @@ module ErrorMessages = struct "An inline record type declaration is only allowed in a variant \ constructor's declaration" - let sameTypeSpread = - "You're using a ... spread without extra fields. This is the same type." - let polyVarIntWithSuffix number = "A numeric polymorphic variant cannot be followed by a letter. Did you \ mean `#" ^ number ^ "`?" @@ -386,7 +383,7 @@ let buildLongident words = let makeInfixOperator (p : Parser.t) token startPos endPos = let stringifiedToken = if token = Token.MinusGreater then - if p.uncurried_config |> Res_uncurried.isDefault then "|.u" else "|." + if p.uncurried_config = Legacy then "|." else "|.u" else if token = Token.PlusPlus then "^" else if token = Token.BangEqual then "<>" else if token = Token.BangEqualEqual then "!=" @@ -516,7 +513,7 @@ let wrapTypeAnnotation ~loc newtypes core_type body = * return a wrapping function that wraps ((__x) => ...) around an expression * e.g. foo(_, 3) becomes (__x) => foo(__x, 3) *) -let processUnderscoreApplication args = +let processUnderscoreApplication (p : Parser.t) args = let exp_question = ref None in let hidden_var = "__x" in let check_arg ((lab, exp) as arg) = @@ -537,7 +534,9 @@ let processUnderscoreApplication args = (Ppat_var (Location.mkloc hidden_var loc)) ~loc:Location.none in - Ast_helper.Exp.mk (Pexp_fun (Nolabel, None, pattern, exp_apply)) ~loc + let funExpr = Ast_helper.Exp.fun_ ~loc Nolabel None pattern exp_apply in + if p.uncurried_config = Legacy then funExpr + else Ast_uncurried.uncurriedFun ~loc ~arity:1 funExpr | None -> exp_apply in (args, wrap) @@ -1558,8 +1557,7 @@ and parseEs6ArrowExpression ?(arrowAttrs = []) ?(arrowStartPos = None) ?context | TermParameter {dotted} :: _ when p.uncurried_config |> Res_uncurried.fromDotted ~dotted && isFun -> true - | TermParameter _ :: rest - when (not (p.uncurried_config |> Res_uncurried.isDefault)) && isFun -> + | TermParameter _ :: rest when p.uncurried_config = Legacy && isFun -> rest |> List.exists (function | TermParameter {dotted} -> dotted @@ -1594,11 +1592,7 @@ and parseEs6ArrowExpression ?(arrowAttrs = []) ?(arrowStartPos = None) ?context let uncurried = p.uncurried_config |> Res_uncurried.fromDotted ~dotted in - if - uncurried - && (termParamNum = 1 - || not (p.uncurried_config |> Res_uncurried.isDefault)) - then + if uncurried && (termParamNum = 1 || p.uncurried_config = Legacy) then (termParamNum - 1, Ast_uncurried.uncurriedFun ~loc ~arity funExpr, 1) else (termParamNum - 1, funExpr, arity + 1) | TypeParameter {dotted = _; attrs; locs = newtypes; pos = startPos} -> @@ -2207,9 +2201,16 @@ and parseBinaryExpr ?(context = OrdinaryExpr) ?a p prec = let b = parseBinaryExpr ~context p tokenPrec in let loc = mkLoc a.Parsetree.pexp_loc.loc_start b.pexp_loc.loc_end in let expr = - Ast_helper.Exp.apply ~loc - (makeInfixOperator p token startPos endPos) - [(Nolabel, a); (Nolabel, b)] + match (token, b.pexp_desc) with + | BarGreater, Pexp_apply (funExpr, args) + when p.uncurried_config = Uncurried -> + {b with pexp_desc = Pexp_apply (funExpr, args @ [(Nolabel, a)])} + | BarGreater, _ when p.uncurried_config = Uncurried -> + Ast_helper.Exp.apply ~loc b [(Nolabel, a)] + | _ -> + Ast_helper.Exp.apply ~loc + (makeInfixOperator p token startPos endPos) + [(Nolabel, a); (Nolabel, b)] in Parser.eatBreadcrumb p; loop expr) @@ -3672,7 +3673,7 @@ and parseCallExpr p funExpr = List.fold_left (fun callBody group -> let dotted, args = group in - let args, wrap = processUnderscoreApplication args in + let args, wrap = processUnderscoreApplication p args in let exp = let uncurried = p.uncurried_config |> Res_uncurried.fromDotted ~dotted @@ -3922,9 +3923,8 @@ and parsePolyTypeExpr p = let returnType = parseTypExpr ~alias:false p in let loc = mkLoc typ.Parsetree.ptyp_loc.loc_start p.prevEndPos in let tFun = Ast_helper.Typ.arrow ~loc Asttypes.Nolabel typ returnType in - if p.uncurried_config |> Res_uncurried.isDefault then - Ast_uncurried.uncurriedType ~loc ~arity:1 tFun - else tFun + if p.uncurried_config = Legacy then tFun + else Ast_uncurried.uncurriedType ~loc ~arity:1 tFun | _ -> Ast_helper.Typ.var ~loc:var.loc var.txt) | _ -> assert false) | _ -> parseTypExpr p @@ -4091,19 +4091,10 @@ and parseRecordOrObjectType ~attrs p = (Diagnostics.message ErrorMessages.forbiddenInlineRecordDeclaration) | _ -> () in - let startFirstField = p.startPos in let fields = parseCommaDelimitedRegion ~grammar:Grammar.StringFieldDeclarations ~closing:Rbrace ~f:parseStringFieldDeclaration p in - let () = - match fields with - | [Parsetree.Oinherit {ptyp_loc}] -> - (* {...x}, spread without extra fields *) - Parser.err p ~startPos:startFirstField ~endPos:ptyp_loc.loc_end - (Diagnostics.message ErrorMessages.sameTypeSpread) - | _ -> () - in Parser.expect Rbrace p; let loc = mkLoc startPos p.prevEndPos in Ast_helper.Typ.object_ ~loc ~attrs fields closedFlag @@ -4134,6 +4125,13 @@ and parseTypeAlias p typ = * | . type_parameter *) and parseTypeParameter p = + let docAttr : Parsetree.attributes = + match p.Parser.token with + | DocComment (loc, s) -> + Parser.next p; + [docCommentToAttribute loc s] + | _ -> [] + in if p.Parser.token = Token.Tilde || p.token = Dot @@ -4141,7 +4139,7 @@ and parseTypeParameter p = then let startPos = p.Parser.startPos in let dotted = Parser.optional p Dot in - let attrs = parseAttributes p in + let attrs = docAttr @ parseAttributes p in match p.Parser.token with | Tilde -> ( Parser.next p; @@ -4245,6 +4243,7 @@ and parseEs6ArrowType ~attrs p = let returnType = parseTypExpr ~alias:false p in let loc = mkLoc startPos p.prevEndPos in Ast_helper.Typ.arrow ~loc ~attrs arg typ returnType + | DocComment _ -> assert false | _ -> let parameters = parseTypeParameters p in Parser.expect EqualGreater p; @@ -4252,7 +4251,7 @@ and parseEs6ArrowType ~attrs p = let endPos = p.prevEndPos in let returnTypeArity = match parameters with - | _ when p.uncurried_config |> Res_uncurried.isDefault -> 0 + | _ when p.uncurried_config <> Legacy -> 0 | _ -> if parameters |> List.exists (function {dotted; typ = _} -> dotted) then 0 @@ -4266,19 +4265,11 @@ and parseEs6ArrowType ~attrs p = let uncurried = p.uncurried_config |> Res_uncurried.fromDotted ~dotted in - if - uncurried - && (paramNum = 1 - || not (p.uncurried_config |> Res_uncurried.isDefault)) - then - let loc = mkLoc startPos endPos in - let tArg = Ast_helper.Typ.arrow ~loc ~attrs argLbl typ t in + let loc = mkLoc startPos endPos in + let tArg = Ast_helper.Typ.arrow ~loc ~attrs argLbl typ t in + if uncurried && (paramNum = 1 || p.uncurried_config = Legacy) then (paramNum - 1, Ast_uncurried.uncurriedType ~loc ~arity tArg, 1) - else - ( paramNum - 1, - Ast_helper.Typ.arrow ~loc:(mkLoc startPos endPos) ~attrs argLbl - typ t, - arity + 1 )) + else (paramNum - 1, tArg, arity + 1)) parameters (List.length parameters, returnType, returnTypeArity + 1) in @@ -4335,9 +4326,8 @@ and parseArrowTypeRest ~es6Arrow ~startPos typ p = let returnType = parseTypExpr ~alias:false p in let loc = mkLoc startPos p.prevEndPos in let arrowTyp = Ast_helper.Typ.arrow ~loc Asttypes.Nolabel typ returnType in - if p.uncurried_config |> Res_uncurried.isDefault then - Ast_uncurried.uncurriedType ~loc ~arity:1 arrowTyp - else arrowTyp + if p.uncurried_config = Legacy then arrowTyp + else Ast_uncurried.uncurriedType ~loc ~arity:1 arrowTyp | _ -> typ and parseTypExprRegion p = @@ -4459,7 +4449,7 @@ and parseFieldDeclaration p = let loc = mkLoc startPos typ.ptyp_loc.loc_end in (optional, Ast_helper.Type.field ~attrs ~loc ~mut name typ) -and parseFieldDeclarationRegion p = +and parseFieldDeclarationRegion ?foundObjectField p = let startPos = p.Parser.startPos in let attrs = parseAttributes p in let mut = @@ -4467,6 +4457,20 @@ and parseFieldDeclarationRegion p = else Asttypes.Immutable in match p.token with + | DotDotDot -> + Parser.next p; + let name = Location.mkloc "..." (mkLoc startPos p.prevEndPos) in + let typ = parsePolyTypeExpr p in + let loc = mkLoc startPos typ.ptyp_loc.loc_end in + Some (Ast_helper.Type.field ~attrs ~loc ~mut name typ) + | String s when foundObjectField <> None -> + Option.get foundObjectField := true; + Parser.next p; + let name = Location.mkloc s (mkLoc startPos p.prevEndPos) in + Parser.expect Colon p; + let typ = parsePolyTypeExpr p in + let loc = mkLoc startPos typ.ptyp_loc.loc_end in + Some (Ast_helper.Type.field ~attrs ~loc ~mut name typ) | Lident _ -> let lident, loc = parseLident p in let name = Location.mkloc lident loc in @@ -4558,8 +4562,6 @@ and parseConstrDeclArgs p = match p.token with | Rbrace -> (* {...x}, spread without extra fields *) - Parser.err ~startPos:dotdotdotStart ~endPos:dotdotdotEnd p - (Diagnostics.message ErrorMessages.sameTypeSpread); Parser.next p | _ -> Parser.expect Comma p in @@ -4921,6 +4923,11 @@ and parseTypeEquationOrConstrDecl p = let arrowType = Ast_helper.Typ.arrow ~loc Asttypes.Nolabel typ returnType in + let uncurried = p.uncurried_config <> Legacy in + let arrowType = + if uncurried then Ast_uncurried.uncurriedType ~loc ~arity:1 arrowType + else arrowType + in let typ = parseTypeAlias p arrowType in (Some typ, Asttypes.Public, Parsetree.Ptype_abstract) | _ -> (Some typ, Asttypes.Public, Parsetree.Ptype_abstract)) @@ -4970,40 +4977,54 @@ and parseRecordOrObjectDecl p = in let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in (Some typ, Asttypes.Public, Parsetree.Ptype_abstract) - | DotDotDot -> + | DotDotDot -> ( let dotdotdotStart = p.startPos in let dotdotdotEnd = p.endPos in (* start of object type spreading, e.g. `type u = {...a, "u": int}` *) Parser.next p; let typ = parseTypExpr p in - let () = - match p.token with - | Rbrace -> - (* {...x}, spread without extra fields *) - Parser.err ~startPos:dotdotdotStart ~endPos:dotdotdotEnd p - (Diagnostics.message ErrorMessages.sameTypeSpread); - Parser.next p - | _ -> Parser.expect Comma p - in - let () = - match p.token with - | Lident _ -> - Parser.err ~startPos:dotdotdotStart ~endPos:dotdotdotEnd p - (Diagnostics.message ErrorMessages.spreadInRecordDeclaration) - | _ -> () - in - let fields = - Parsetree.Oinherit typ - :: parseCommaDelimitedRegion ~grammar:Grammar.StringFieldDeclarations - ~closing:Rbrace ~f:parseStringFieldDeclaration p - in - Parser.expect Rbrace p; - let loc = mkLoc startPos p.prevEndPos in - let typ = - Ast_helper.Typ.object_ ~loc fields Asttypes.Closed |> parseTypeAlias p - in - let typ = parseArrowTypeRest ~es6Arrow:true ~startPos typ p in - (Some typ, Asttypes.Public, Parsetree.Ptype_abstract) + match p.token with + | Rbrace -> + (* {...x}, spread without extra fields *) + Parser.next p; + let loc = mkLoc startPos p.prevEndPos in + let dotField = + Ast_helper.Type.field ~loc + {txt = "..."; loc = mkLoc dotdotdotStart dotdotdotEnd} + typ + in + let kind = Parsetree.Ptype_record [dotField] in + (None, Public, kind) + | _ -> + Parser.expect Comma p; + let loc = mkLoc startPos p.prevEndPos in + let dotField = + Ast_helper.Type.field ~loc + {txt = "..."; loc = mkLoc dotdotdotStart dotdotdotEnd} + typ + in + let foundObjectField = ref false in + let fields = + parseCommaDelimitedRegion ~grammar:Grammar.RecordDecl ~closing:Rbrace + ~f:(parseFieldDeclarationRegion ~foundObjectField) + p + in + Parser.expect Rbrace p; + if !foundObjectField then + let fields = + Ext_list.map fields (fun ld -> + match ld.pld_name.txt with + | "..." -> Parsetree.Oinherit ld.pld_type + | _ -> Otag (ld.pld_name, ld.pld_attributes, ld.pld_type)) + in + let dotField = Parsetree.Oinherit typ in + let typ_obj = Ast_helper.Typ.object_ (dotField :: fields) Closed in + let typ_obj = parseTypeAlias p typ_obj in + let typ_obj = parseArrowTypeRest ~es6Arrow:true ~startPos typ_obj p in + (Some typ_obj, Public, Ptype_abstract) + else + let kind = Parsetree.Ptype_record (dotField :: fields) in + (None, Public, kind)) | _ -> ( let attrs = parseAttributes p in match p.Parser.token with @@ -6386,15 +6407,17 @@ and parseAttribute p = Some (attrId, payload) | DocComment (loc, s) -> Parser.next p; - Some - ( {txt = "res.doc"; loc}, - PStr - [ - Ast_helper.Str.eval ~loc - (Ast_helper.Exp.constant ~loc (Pconst_string (s, None))); - ] ) + Some (docCommentToAttribute loc s) | _ -> None +and docCommentToAttribute loc s : Parsetree.attribute = + ( {txt = "res.doc"; loc}, + PStr + [ + Ast_helper.Str.eval ~loc + (Ast_helper.Exp.constant ~loc (Pconst_string (s, None))); + ] ) + and parseAttributes p = parseRegion p ~grammar:Grammar.Attribute ~f:parseAttribute @@ -6409,10 +6432,12 @@ and parseStandaloneAttribute p = let attrId = parseAttributeId ~startPos p in let attrId = match attrId.txt with + | "uncurried.swap" -> + p.uncurried_config <- Config.Swap; + attrId | "uncurried" -> - p.uncurried_config <- Res_uncurried.Default; + p.uncurried_config <- Config.Uncurried; attrId - | "toUncurried" -> {attrId with txt = "uncurried"} | _ -> attrId in let payload = parsePayload p in @@ -6465,4 +6490,4 @@ let parseSpecification p : Parsetree.signature = (* module structure on the file level *) let parseImplementation p : Parsetree.structure = - parseRegion p ~grammar:Grammar.Implementation ~f:parseStructureItemRegion + parseRegion p ~grammar:Grammar.Implementation ~f:parseStructureItemRegion \ No newline at end of file diff --git a/analysis/vendor/res_syntax/res_grammar.ml b/analysis/vendor/res_syntax/res_grammar.ml index cba9b4bde..f40cd6264 100644 --- a/analysis/vendor/res_syntax/res_grammar.ml +++ b/analysis/vendor/res_syntax/res_grammar.ml @@ -192,7 +192,7 @@ let isFieldDeclStart = function | _ -> false let isRecordDeclStart = function - | Token.At | Mutable | Lident _ -> true + | Token.At | Mutable | Lident _ | DotDotDot | String _ -> true | _ -> false let isTypExprStart = function diff --git a/analysis/vendor/res_syntax/res_multi_printer.ml b/analysis/vendor/res_syntax/res_multi_printer.ml index 6865703be..551ab5bbf 100644 --- a/analysis/vendor/res_syntax/res_multi_printer.ml +++ b/analysis/vendor/res_syntax/res_multi_printer.ml @@ -1,7 +1,65 @@ let defaultPrintWidth = 100 +(* Determine if the file is in uncurried mode by looking for + the fist ancestor .bsconfig and see if it contains "uncurried": true *) +let getUncurriedFromBsconfig ~filename = + let rec findBsconfig ~dir = + let bsconfig = Filename.concat dir "bsconfig.json" in + if Sys.file_exists bsconfig then Some (Res_io.readFile ~filename:bsconfig) + else + let parent = Filename.dirname dir in + if parent = dir then None else findBsconfig ~dir:parent + in + let rec findFromNodeModules ~dir = + let parent = Filename.dirname dir in + if Filename.basename dir = "node_modules" then + let bsconfig = Filename.concat parent "bsconfig.json" in + if Sys.file_exists bsconfig then Some (Res_io.readFile ~filename:bsconfig) + else None + else if parent = dir then None + else findFromNodeModules ~dir:parent + in + let dir = + if Filename.is_relative filename then + Filename.dirname (Filename.concat (Sys.getcwd ()) filename) + else Filename.dirname filename + in + let bsconfig () = + match findBsconfig ~dir with + | None -> + (* The editor calls format on a temporary file. So bsconfig can't be found. + This looks outside the node_modules containing the bsc binary *) + let dir = (Filename.dirname Sys.argv.(0) [@doesNotRaise]) in + findFromNodeModules ~dir + | x -> x + in + match bsconfig () with + | exception _ -> () + | None -> () + | Some bsconfig -> + let lines = bsconfig |> String.split_on_char '\n' in + let uncurried = + lines + |> List.exists (fun line -> + let uncurried = ref false in + let true_ = ref false in + let words = line |> String.split_on_char ' ' in + words + |> List.iter (fun word -> + match word with + | "\"uncurried\"" | "\"uncurried\":" -> uncurried := true + | "\"uncurried\":true" | "\"uncurried\":true," -> + uncurried := true; + true_ := true + | "true" | ":true" | "true," | ":true," -> true_ := true + | _ -> ()); + !uncurried && !true_) + in + if uncurried then Config.uncurried := Uncurried + (* print res files to res syntax *) let printRes ~ignoreParseErrors ~isInterface ~filename = + getUncurriedFromBsconfig ~filename; if isInterface then ( let parseResult = Res_driver.parsingEngine.parseInterface ~forPrinter:true ~filename diff --git a/analysis/vendor/res_syntax/res_parens.ml b/analysis/vendor/res_syntax/res_parens.ml index d6628c872..13e801b5c 100644 --- a/analysis/vendor/res_syntax/res_parens.ml +++ b/analysis/vendor/res_syntax/res_parens.ml @@ -55,6 +55,7 @@ let callExpr expr = | Pexp_try _ | Pexp_while _ | Pexp_for _ | Pexp_ifthenelse _ ); } -> Parenthesized + | _ when Ast_uncurried.exprIsUncurriedFun expr -> Parenthesized | _ when ParsetreeViewer.hasAwaitAttribute expr.pexp_attributes -> Parenthesized | _ -> Nothing) @@ -131,6 +132,7 @@ let binaryExprOperand ~isLhs expr = Pexp_constraint _ | Pexp_fun _ | Pexp_function _ | Pexp_newtype _; } -> Parenthesized + | _ when Ast_uncurried.exprIsUncurriedFun expr -> Parenthesized | expr when ParsetreeViewer.isBinaryExpression expr -> Parenthesized | expr when ParsetreeViewer.isTernaryExpr expr -> Parenthesized | {pexp_desc = Pexp_lazy _ | Pexp_assert _} when isLhs -> Parenthesized @@ -440,6 +442,7 @@ let includeModExpr modExpr = let arrowReturnTypExpr typExpr = match typExpr.Parsetree.ptyp_desc with | Parsetree.Ptyp_arrow _ -> true + | _ when Ast_uncurried.typeIsUncurriedFun typExpr -> true | _ -> false let patternRecordRowRhs (pattern : Parsetree.pattern) = diff --git a/analysis/vendor/res_syntax/res_parser.ml b/analysis/vendor/res_syntax/res_parser.ml index 387172a36..ca39cfcf8 100644 --- a/analysis/vendor/res_syntax/res_parser.ml +++ b/analysis/vendor/res_syntax/res_parser.ml @@ -22,7 +22,7 @@ type t = { mutable diagnostics: Diagnostics.t list; mutable comments: Comment.t list; mutable regions: regionStatus ref list; - mutable uncurried_config: Res_uncurried.config; + mutable uncurried_config: Config.uncurried; } let err ?startPos ?endPos p error = @@ -122,7 +122,7 @@ let make ?(mode = ParseForTypeChecker) src filename = diagnostics = []; comments = []; regions = [ref Report]; - uncurried_config = Res_uncurried.init; + uncurried_config = !Config.uncurried; } in parserState.scanner.err <- diff --git a/analysis/vendor/res_syntax/res_parser.mli b/analysis/vendor/res_syntax/res_parser.mli index 8a00c722e..9544a7cc2 100644 --- a/analysis/vendor/res_syntax/res_parser.mli +++ b/analysis/vendor/res_syntax/res_parser.mli @@ -21,7 +21,7 @@ type t = { mutable diagnostics: Diagnostics.t list; mutable comments: Comment.t list; mutable regions: regionStatus ref list; - mutable uncurried_config: Res_uncurried.config; + mutable uncurried_config: Config.uncurried; } val make : ?mode:mode -> string -> string -> t diff --git a/analysis/vendor/res_syntax/res_parsetree_viewer.ml b/analysis/vendor/res_syntax/res_parsetree_viewer.ml index 1d2b43804..30d24b7cc 100644 --- a/analysis/vendor/res_syntax/res_parsetree_viewer.ml +++ b/analysis/vendor/res_syntax/res_parsetree_viewer.ml @@ -109,7 +109,12 @@ let collectListExpressions expr = (* (__x) => f(a, __x, c) -----> f(a, _, c) *) let rewriteUnderscoreApply expr = - match expr.pexp_desc with + let expr_fun = + if Ast_uncurried.exprIsUncurriedFun expr then + Ast_uncurried.exprExtractUncurriedFun expr + else expr + in + match expr_fun.pexp_desc with | Pexp_fun ( Nolabel, None, diff --git a/analysis/vendor/res_syntax/res_printer.ml b/analysis/vendor/res_syntax/res_printer.ml index 995d12c72..2f6ef766d 100644 --- a/analysis/vendor/res_syntax/res_printer.ml +++ b/analysis/vendor/res_syntax/res_printer.ml @@ -575,9 +575,9 @@ let printOptionalLabel attrs = module State = struct let customLayoutThreshold = 2 - type t = {customLayout: int; mutable uncurried_config: Res_uncurried.config} + type t = {customLayout: int; mutable uncurried_config: Config.uncurried} - let init = {customLayout = 0; uncurried_config = Res_uncurried.init} + let init () = {customLayout = 0; uncurried_config = !Config.uncurried} let nextCustomLayout t = {t with customLayout = t.customLayout + 1} @@ -1531,9 +1531,12 @@ and printLabelDeclaration ~state (ld : Parsetree.label_declaration) cmtTbl = | Mutable -> Doc.text "mutable " | Immutable -> Doc.nil in - let name = - let doc = printIdentLike ld.pld_name.txt in - printComments doc cmtTbl ld.pld_name.loc + let name, isDot = + let doc, isDot = + if ld.pld_name.txt = "..." then (Doc.text ld.pld_name.txt, true) + else (printIdentLike ld.pld_name.txt, false) + in + (printComments doc cmtTbl ld.pld_name.loc, isDot) in let optional = printOptionalLabel ld.pld_attributes in Doc.group @@ -1543,7 +1546,7 @@ and printLabelDeclaration ~state (ld : Parsetree.label_declaration) cmtTbl = mutableFlag; name; optional; - Doc.text ": "; + (if isDot then Doc.nil else Doc.text ": "); printTypExpr ~state ld.pld_type cmtTbl; ]) @@ -1644,6 +1647,7 @@ and printTypExpr ~(state : State.t) (typExpr : Parsetree.core_type) cmtTbl = let needsParens = match typ.ptyp_desc with | Ptyp_arrow _ -> true + | _ when Ast_uncurried.typeIsUncurriedFun typ -> true | _ -> false in let doc = printTypExpr ~state typ cmtTbl in @@ -2667,18 +2671,32 @@ and printExpression ~state (e : Parsetree.expression) cmtTbl = (Doc.concat [attrs; parametersDoc; typConstraintDoc; Doc.text " =>"; returnExprDoc]) in + let uncurried = Ast_uncurried.exprIsUncurriedFun e in + let e_fun = + if uncurried then Ast_uncurried.exprExtractUncurriedFun e else e + in let printedExpression = - match e.pexp_desc with + match e_fun.pexp_desc with | Pexp_fun ( Nolabel, None, {ppat_desc = Ppat_var {txt = "__x"}}, - {pexp_desc = Pexp_apply _} ) -> + {pexp_desc = Pexp_apply _} ) + | Pexp_construct + ( {txt = Lident "Function$"}, + Some + { + pexp_desc = + Pexp_fun + ( Nolabel, + None, + {ppat_desc = Ppat_var {txt = "__x"}}, + {pexp_desc = Pexp_apply _} ); + } ) -> (* (__x) => f(a, __x, c) -----> f(a, _, c) *) printExpressionWithComments ~state - (ParsetreeViewer.rewriteUnderscoreApply e) + (ParsetreeViewer.rewriteUnderscoreApply e_fun) cmtTbl - | _ when Ast_uncurried.exprIsUncurriedFun e -> printArrow e | Pexp_fun _ | Pexp_newtype _ -> printArrow e | Parsetree.Pexp_constant c -> printConstant ~templateLiteral:(ParsetreeViewer.isTemplateLiteral e) c @@ -5276,12 +5294,12 @@ and printAttribute ?(standalone = false) ~state | _ -> let id = match id.txt with + | "uncurried.swap" -> + state.uncurried_config <- Config.Swap; + id | "uncurried" -> - state.uncurried_config <- Res_uncurried.Default; + state.uncurried_config <- Config.Uncurried; id - | "toUncurried" -> - state.uncurried_config <- Res_uncurried.Default; - {id with txt = "uncurried"} | _ -> id in ( Doc.group @@ -5557,22 +5575,22 @@ and printExtensionConstructor ~state (constr : Parsetree.extension_constructor) in Doc.concat [bar; Doc.group (Doc.concat [attrs; name; kind])] -let printTypeParams = printTypeParams ~state:State.init -let printTypExpr = printTypExpr ~state:State.init -let printExpression = printExpression ~state:State.init -let printPattern = printPattern ~state:State.init +let printTypeParams params = printTypeParams ~state:(State.init ()) params +let printTypExpr t = printTypExpr ~state:(State.init ()) t +let printExpression e = printExpression ~state:(State.init ()) e +let printPattern p = printPattern ~state:(State.init ()) p let printImplementation ~width (s : Parsetree.structure) ~comments = let cmtTbl = CommentTable.make () in CommentTable.walkStructure s cmtTbl comments; (* CommentTable.log cmtTbl; *) - let doc = printStructure ~state:State.init s cmtTbl in + let doc = printStructure ~state:(State.init ()) s cmtTbl in (* Doc.debug doc; *) Doc.toString ~width doc ^ "\n" let printInterface ~width (s : Parsetree.signature) ~comments = let cmtTbl = CommentTable.make () in CommentTable.walkSignature s cmtTbl comments; - Doc.toString ~width (printSignature ~state:State.init s cmtTbl) ^ "\n" + Doc.toString ~width (printSignature ~state:(State.init ()) s cmtTbl) ^ "\n" -let printStructure = printStructure ~state:State.init +let printStructure = printStructure ~state:(State.init ()) diff --git a/analysis/vendor/res_syntax/res_printer_state.ml b/analysis/vendor/res_syntax/res_printer_state.ml deleted file mode 100644 index 882b38965..000000000 --- a/analysis/vendor/res_syntax/res_printer_state.ml +++ /dev/null @@ -1,18 +0,0 @@ -let customLayoutThreshold = 2 - -type t = { - customLayout: int; - mutable uncurried_config: Res_uncurried.config; - customInfixOperators: (string, string) Hashtbl.t; -} - -let init = - { - customLayout = 0; - uncurried_config = Res_uncurried.init; - customInfixOperators = Hashtbl.create 0; - } - -let nextCustomLayout t = {t with customLayout = t.customLayout + 1} - -let shouldBreakCallback t = t.customLayout > customLayoutThreshold diff --git a/analysis/vendor/res_syntax/res_uncurried.ml b/analysis/vendor/res_syntax/res_uncurried.ml index d3c666c4d..1a777e159 100644 --- a/analysis/vendor/res_syntax/res_uncurried.ml +++ b/analysis/vendor/res_syntax/res_uncurried.ml @@ -1,17 +1,11 @@ -type config = Legacy | Default - -let init = Legacy - -let isDefault = function - | Legacy -> false - | Default -> true - (* For parsing *) let fromDotted ~dotted = function - | Legacy -> dotted - | Default -> not dotted + | Config.Legacy -> dotted + | Swap -> not dotted + | Uncurried -> true (* For printing *) let getDotted ~uncurried = function - | Legacy -> uncurried - | Default -> not uncurried + | Config.Legacy -> uncurried + | Swap -> not uncurried + | Uncurried -> false