diff --git a/vendor/parser-standard/ast_helper.ml b/vendor/parser-standard/ast_helper.ml index ae65b50931..184049f0cb 100644 --- a/vendor/parser-standard/ast_helper.ml +++ b/vendor/parser-standard/ast_helper.ml @@ -72,6 +72,7 @@ module Typ = struct let poly ?loc ?attrs a b = mk ?loc ?attrs (Ptyp_poly (a, b)) let package ?loc ?attrs a b = mk ?loc ?attrs (Ptyp_package (a, b)) let extension ?loc ?attrs a = mk ?loc ?attrs (Ptyp_extension a) + let open_ ?loc ?attrs mod_ident t = mk ?loc ?attrs (Ptyp_open (mod_ident, t)) let force_poly t = match t.ptyp_desc with @@ -102,9 +103,9 @@ module Typ = struct Ptyp_object (List.map loop_object_field lst, o) | Ptyp_class (longident, lst) -> Ptyp_class (longident, List.map loop lst) - | Ptyp_alias(core_type, string) -> - check_variable var_names t.ptyp_loc string; - Ptyp_alias(loop core_type, string) + | Ptyp_alias(core_type, alias) -> + check_variable var_names alias.loc alias.txt; + Ptyp_alias(loop core_type, alias) | Ptyp_variant(row_field_list, flag, lbl_lst_option) -> Ptyp_variant(List.map loop_row_field row_field_list, flag, lbl_lst_option) @@ -114,6 +115,8 @@ module Typ = struct Ptyp_poly(string_lst, loop core_type) | Ptyp_package(longident,lst) -> Ptyp_package(longident,List.map (fun (n,typ) -> (n,loop typ) ) lst) + | Ptyp_open (mod_ident, core_type) -> + Ptyp_open (mod_ident, loop core_type) | Ptyp_extension (s, arg) -> Ptyp_extension (s, arg) in @@ -178,8 +181,7 @@ module Exp = struct let ident ?loc ?attrs a = mk ?loc ?attrs (Pexp_ident a) let constant ?loc ?attrs a = mk ?loc ?attrs (Pexp_constant a) let let_ ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_let (a, b, c)) - let fun_ ?loc ?attrs a b c d = mk ?loc ?attrs (Pexp_fun (a, b, c, d)) - let function_ ?loc ?attrs a = mk ?loc ?attrs (Pexp_function a) + let function_ ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_function (a, b, c)) let apply ?loc ?attrs a b = mk ?loc ?attrs (Pexp_apply (a, b)) let match_ ?loc ?attrs a b = mk ?loc ?attrs (Pexp_match (a, b)) let try_ ?loc ?attrs a b = mk ?loc ?attrs (Pexp_try (a, b)) @@ -213,7 +215,9 @@ module Exp = struct mk ?loc ?attrs (Pexp_letop {let_; ands; body}) let extension ?loc ?attrs a = mk ?loc ?attrs (Pexp_extension a) let unreachable ?loc ?attrs () = mk ?loc ?attrs Pexp_unreachable - let hole ?loc ?attrs () = mk ?loc ?attrs Pexp_hole + (* Added *) + let hole ?loc ?attrs () = mk ?loc ?attrs Pexp_hole + (* *) let case lhs ?guard rhs = { @@ -259,7 +263,9 @@ module Mod = struct let constraint_ ?loc ?attrs m mty = mk ?loc ?attrs (Pmod_constraint (m, mty)) let unpack ?loc ?attrs e = mk ?loc ?attrs (Pmod_unpack e) let extension ?loc ?attrs a = mk ?loc ?attrs (Pmod_extension a) + (* Added *) let hole ?loc ?attrs () = mk ?loc ?attrs Pmod_hole + (* *) end module Sig = struct diff --git a/vendor/parser-standard/ast_mapper.ml b/vendor/parser-standard/ast_mapper.ml index 0bb017ddfc..3a40592616 100644 --- a/vendor/parser-standard/ast_mapper.ml +++ b/vendor/parser-standard/ast_mapper.ml @@ -20,6 +20,9 @@ (* Ensure that record patterns don't miss any field. *) *) +[@@@ocaml.warning "-60"] module Str = Ast_helper.Str (* For ocamldep *) +[@@@ocaml.warning "+60"] + open Parsetree open Ast_helper open Location @@ -45,6 +48,7 @@ type mapper = { constant: mapper -> constant -> constant; constructor_declaration: mapper -> constructor_declaration -> constructor_declaration; + directive_argument: mapper -> directive_argument -> directive_argument; expr: mapper -> expression -> expression; extension: mapper -> extension -> extension; extension_constructor: mapper -> extension_constructor @@ -68,6 +72,8 @@ type mapper = { signature_item: mapper -> signature_item -> signature_item; structure: mapper -> structure -> structure; structure_item: mapper -> structure_item -> structure_item; + toplevel_directive: mapper -> toplevel_directive -> toplevel_directive; + toplevel_phrase: mapper -> toplevel_phrase -> toplevel_phrase; typ: mapper -> core_type -> core_type; type_declaration: mapper -> type_declaration -> type_declaration; type_extension: mapper -> type_extension -> type_extension; @@ -76,9 +82,6 @@ type mapper = { value_binding: mapper -> value_binding -> value_binding; value_description: mapper -> value_description -> value_description; with_constraint: mapper -> with_constraint -> with_constraint; - directive_argument: mapper -> directive_argument -> directive_argument; - toplevel_directive: mapper -> toplevel_directive -> toplevel_directive; - toplevel_phrase: mapper -> toplevel_phrase -> toplevel_phrase; } let map_fst f (x, y) = (f x, y) @@ -147,7 +150,9 @@ module T = struct object_ ~loc ~attrs (List.map (object_field sub) l) o | Ptyp_class (lid, tl) -> class_ ~loc ~attrs (map_loc sub lid) (List.map (sub.typ sub) tl) - | Ptyp_alias (t, s) -> alias ~loc ~attrs (sub.typ sub t) s + | Ptyp_alias (t, s) -> + let s = map_loc sub s in + alias ~loc ~attrs (sub.typ sub t) s | Ptyp_variant (rl, b, ll) -> variant ~loc ~attrs (List.map (row_field sub) rl) b ll | Ptyp_poly (sl, t) -> poly ~loc ~attrs @@ -155,6 +160,8 @@ module T = struct | Ptyp_package (lid, l) -> package ~loc ~attrs (map_loc sub lid) (List.map (map_tuple (map_loc sub) (sub.typ sub)) l) + | Ptyp_open (mod_ident, t) -> + open_ ~loc ~attrs (map_loc sub mod_ident) (sub.typ sub t) | Ptyp_extension x -> extension ~loc ~attrs (sub.extension sub x) let map_type_declaration sub @@ -360,7 +367,9 @@ module M = struct (sub.module_type sub mty) | Pmod_unpack e -> unpack ~loc ~attrs (sub.expr sub e) | Pmod_extension x -> extension ~loc ~attrs (sub.extension sub x) + (* Added *) | Pmod_hole -> hole ~loc ~attrs () + (* *) let map_structure_item sub {pstr_loc = loc; pstr_desc = desc} = let open Str in @@ -391,6 +400,35 @@ end module E = struct (* Value expressions for the core language *) + let map_function_param sub { pparam_loc = loc; pparam_desc = desc } = + let loc = sub.location sub loc in + let desc = + match desc with + | Pparam_val (lab, def, p) -> + Pparam_val + (lab, + map_opt (sub.expr sub) def, + sub.pat sub p) + | Pparam_newtype ty -> + Pparam_newtype (map_loc sub ty) + in + { pparam_loc = loc; pparam_desc = desc } + + let map_function_body sub body = + match body with + | Pfunction_body e -> + Pfunction_body (sub.expr sub e) + | Pfunction_cases (cases, loc, attributes) -> + let cases = sub.cases sub cases in + let loc = sub.location sub loc in + let attributes = sub.attributes sub attributes in + Pfunction_cases (cases, loc, attributes) + + let map_constraint sub c = + match c with + | Pconstraint ty -> Pconstraint (sub.typ sub ty) + | Pcoerce (ty1, ty2) -> Pcoerce (map_opt (sub.typ sub) ty1, sub.typ sub ty2) + let map sub {pexp_loc = loc; pexp_desc = desc; pexp_attributes = attrs} = let open Exp in let loc = sub.location sub loc in @@ -401,10 +439,11 @@ module E = struct | Pexp_let (r, vbs, e) -> let_ ~loc ~attrs r (List.map (sub.value_binding sub) vbs) (sub.expr sub e) - | Pexp_fun (lab, def, p, e) -> - fun_ ~loc ~attrs lab (map_opt (sub.expr sub) def) (sub.pat sub p) - (sub.expr sub e) - | Pexp_function pel -> function_ ~loc ~attrs (sub.cases sub pel) + | Pexp_function (ps, c, b) -> + function_ ~loc ~attrs + (List.map (map_function_param sub) ps) + (map_opt (map_constraint sub) c) + (map_function_body sub b) | Pexp_apply (e, l) -> apply ~loc ~attrs (sub.expr sub e) (List.map (map_snd (sub.expr sub)) l) | Pexp_match (e, pel) -> @@ -469,7 +508,9 @@ module E = struct (List.map (sub.binding_op sub) ands) (sub.expr sub body) | Pexp_extension x -> extension ~loc ~attrs (sub.extension sub x) | Pexp_unreachable -> unreachable ~loc ~attrs () + (* Added *) | Pexp_hole -> hole ~loc ~attrs () + (* *) let map_binding_op sub {pbop_op; pbop_pat; pbop_exp; pbop_loc} = let open Exp in diff --git a/vendor/parser-standard/lexer.mll b/vendor/parser-standard/lexer.mll index dcaa9d89d1..d74edb17e7 100644 --- a/vendor/parser-standard/lexer.mll +++ b/vendor/parser-standard/lexer.mll @@ -107,7 +107,34 @@ let get_stored_string () = Buffer.contents string_buffer let store_string_char c = Buffer.add_char string_buffer c let store_string_utf_8_uchar u = Buffer.add_utf_8_uchar string_buffer u let store_string s = Buffer.add_string string_buffer s +let store_substring s ~pos ~len = Buffer.add_substring string_buffer s pos len + let store_lexeme lexbuf = store_string (Lexing.lexeme lexbuf) +let store_normalized_newline newline = + (* #12502: we normalize "\r\n" to "\n" at lexing time, + to avoid behavior difference due to OS-specific + newline characters in string literals. + + (For example, Git for Windows will translate \n in versioned + files into \r\n sequences when checking out files on Windows. If + your code contains multiline quoted string literals, the raw + content of the string literal would be different between Git for + Windows users and all other users. Thanks to newline + normalization, the value of the literal as a string constant will + be the same no matter which programming tools are used.) + + Many programming languages use the same approach, for example + Java, Javascript, Kotlin, Python, Swift and C++. + *) + (* Our 'newline' regexp accepts \r*\n, but we only wish + to normalize \r?\n into \n -- see the discussion in #12502. + All carriage returns except for the (optional) last one + are reproduced in the output. We implement this by skipping + the first carriage return, if any. *) + let len = String.length newline in + if len = 1 + then store_string_char '\n' + else store_substring newline ~pos:1 ~len:(len - 1) (* To store the position of the beginning of a string and comment *) let string_start_loc = ref Location.none @@ -338,7 +365,7 @@ let prepare_error loc = function Location.error ~loc ~sub msg | Keyword_as_label kwd -> Location.errorf ~loc - "`%s' is a keyword, it cannot be used as label name" kwd + "%a is a keyword, it cannot be used as label name" Style.inline_code kwd | Invalid_literal s -> Location.errorf ~loc "Invalid literal %s" s | Invalid_directive (dir, explanation) -> @@ -403,6 +430,7 @@ let hex_float_literal = ('.' ['0'-'9' 'A'-'F' 'a'-'f' '_']* )? (['p' 'P'] ['+' '-']? ['0'-'9'] ['0'-'9' '_']* )? let literal_modifier = ['G'-'Z' 'g'-'z'] +let raw_ident_escape = "\\#" rule token = parse | ('\\' as bs) newline { @@ -421,6 +449,8 @@ rule token = parse | ".~" { error lexbuf (Reserved_sequence (".~", Some "is reserved for use in MetaOCaml")) } + | "~" raw_ident_escape (lowercase identchar * as name) ':' + { LABEL name } | "~" (lowercase identchar * as name) ':' { check_label_name lexbuf name; LABEL name } @@ -429,12 +459,16 @@ rule token = parse LABEL name } | "?" { QUESTION } + | "?" raw_ident_escape (lowercase identchar * as name) ':' + { OPTLABEL name } | "?" (lowercase identchar * as name) ':' { check_label_name lexbuf name; OPTLABEL name } | "?" (lowercase_latin1 identchar_latin1 * as name) ':' { warn_latin1 lexbuf; OPTLABEL name } + | raw_ident_escape (lowercase identchar * as name) + { LIDENT name } | lowercase identchar * as name { try Hashtbl.find keyword_table name with Not_found -> LIDENT name } @@ -493,7 +527,7 @@ rule token = parse { CHAR(char_for_octal_code lexbuf 3) } | "\'\\" 'x' ['0'-'9' 'a'-'f' 'A'-'F'] ['0'-'9' 'a'-'f' 'A'-'F'] "\'" { CHAR(char_for_hexadecimal_code lexbuf 3) } - | "\'" ("\\" _ as esc) + | "\'" ("\\" [^ '#'] as esc) { error lexbuf (Illegal_escape (esc, None)) } | "\'\'" { error lexbuf Empty_character_literal } @@ -676,9 +710,11 @@ and comment = parse comment lexbuf } | "\'\'" { store_lexeme lexbuf; comment lexbuf } - | "\'" newline "\'" + | "\'" (newline as nl) "\'" { update_loc lexbuf None 1 false 1; - store_lexeme lexbuf; + store_string_char '\''; + store_normalized_newline nl; + store_string_char '\''; comment lexbuf } | "\'" [^ '\\' '\'' '\010' '\013' ] "\'" @@ -699,9 +735,9 @@ and comment = parse comment_start_loc := []; error_loc loc (Unterminated_comment start) } - | newline + | newline as nl { update_loc lexbuf None 1 false 0; - store_lexeme lexbuf; + store_normalized_newline nl; comment lexbuf } | ident @@ -712,9 +748,13 @@ and comment = parse and string = parse '\"' { lexbuf.lex_start_p } - | '\\' newline ([' ' '\t'] * as space) + | '\\' (newline as nl) ([' ' '\t'] * as space) { update_loc lexbuf None 1 false (String.length space); - if in_comment () then store_lexeme lexbuf; + if in_comment () then begin + store_string_char '\\'; + store_normalized_newline nl; + store_string space; + end; string lexbuf } | '\\' (['\\' '\'' '\"' 'n' 't' 'b' 'r' ' '] as c) @@ -743,11 +783,9 @@ and string = parse store_lexeme lexbuf; string lexbuf } - | newline - { if not (in_comment ()) then - Location.prerr_warning (Location.curr lexbuf) Warnings.Eol_in_string; - update_loc lexbuf None 1 false 0; - store_lexeme lexbuf; + | newline as nl + { update_loc lexbuf None 1 false 0; + store_normalized_newline nl; string lexbuf } | eof @@ -758,9 +796,9 @@ and string = parse string lexbuf } and quoted_string delim = parse - | newline + | newline as nl { update_loc lexbuf None 1 false 0; - store_lexeme lexbuf; + store_normalized_newline nl; quoted_string delim lexbuf } | eof diff --git a/vendor/parser-standard/parser.mly b/vendor/parser-standard/parser.mly index 3785f49787..ba160f09c6 100644 --- a/vendor/parser-standard/parser.mly +++ b/vendor/parser-standard/parser.mly @@ -24,6 +24,9 @@ %{ +[@@@ocaml.warning "-60"] module Str = Ast_helper.Str (* For ocamldep *) +[@@@ocaml.warning "+60"] + open Asttypes open Longident open Parsetree @@ -164,6 +167,10 @@ let mkuplus ~oploc name arg = | _ -> Pexp_apply(mkoperator ~loc:oploc ("~" ^ name), [Nolabel, arg]) +let mk_attr ~loc name payload = + Builtin_attributes.(register_attr Parser name); + Attr.mk ~loc name payload + (* TODO define an abstraction boundary between locations-as-pairs and locations-as-Location.t; it should be clear when we move from one world to the other *) @@ -206,11 +213,13 @@ let rec mktailpat nilloc = let open Location in function let mkstrexp e attrs = { pstr_desc = Pstr_eval (e, attrs); pstr_loc = e.pexp_loc } -let mkexp_constraint ~loc e (t1, t2) = - match t1, t2 with - | Some t, None -> mkexp ~loc (Pexp_constraint(e, t)) - | _, Some t -> mkexp ~loc (Pexp_coerce(e, t1, t)) - | None, None -> assert false +let mkexp_desc_constraint e t = + match t with + | Pconstraint t -> Pexp_constraint(e, t) + | Pcoerce(t1, t2) -> Pexp_coerce(e, t1, t2) + +let mkexp_constraint ~loc e t = + mkexp ~loc (mkexp_desc_constraint e t) let mkexp_opt_constraint ~loc e = function | None -> e @@ -584,6 +593,64 @@ let class_of_let_bindings ~loc lbs body = assert (lbs.lbs_extension = None); mkclass ~loc (Pcl_let (lbs.lbs_rec, List.rev bindings, body)) +(* If all the parameters are [Pparam_newtype x], then return [Some xs] where + [xs] is the corresponding list of values [x]. This function is optimized for + the common case, where a list of parameters contains at least one value + parameter. +*) +let all_params_as_newtypes = + let is_newtype { pparam_desc; _ } = + match pparam_desc with + | Pparam_newtype _ -> true + | Pparam_val _ -> false + in + let as_newtype { pparam_desc; pparam_loc } = + match pparam_desc with + | Pparam_newtype x -> Some (x, pparam_loc) + | Pparam_val _ -> None + in + fun params -> + if List.for_all is_newtype params + then Some (List.filter_map as_newtype params) + else None + +(* Given a construct [fun (type a b c) : t -> e], we construct + [Pexp_newtype(a, Pexp_newtype(b, Pexp_newtype(c, Pexp_constraint(e, t))))] + rather than a [Pexp_function]. +*) +let mkghost_newtype_function_body newtypes body_constraint body = + let wrapped_body = + match body_constraint with + | None -> body + | Some body_constraint -> + let loc = { body.pexp_loc with loc_ghost = true } in + Exp.mk (mkexp_desc_constraint body body_constraint) ~loc + in + let expr = + List.fold_right + (fun (newtype, newtype_loc) e -> + (* Mints a ghost location that approximates the newtype's "extent" as + being from the start of the newtype param until the end of the + function body. + *) + let loc = (newtype_loc.Location.loc_start, body.pexp_loc.loc_end) in + ghexp (Pexp_newtype (newtype, e)) ~loc) + newtypes + wrapped_body + in + expr.pexp_desc + +let mkfunction params body_constraint body = + match body with + | Pfunction_cases _ -> Pexp_function (params, body_constraint, body) + | Pfunction_body body_exp -> + (* If all the params are newtypes, then we don't create a function node; + we create nested newtype nodes. *) + match all_params_as_newtypes params with + | None -> Pexp_function (params, body_constraint, body) + | Some newtypes -> + mkghost_newtype_function_body newtypes body_constraint body_exp + (* Alternatively, we could keep the generic module type in the Parsetree and extract the package type during type-checking. In that case, the assertions below should be turned into explicit checks. *) @@ -1000,6 +1067,27 @@ reversed_nonempty_llist(X): xs = rev(reversed_nonempty_llist(X)) { xs } +(* [reversed_nonempty_concat(X)] recognizes a nonempty sequence of [X]s (each of + which is a list), and produces an OCaml list of their concatenation in + reverse order -- that is, the last element of the last list in the input text + appears first in the list. +*) +reversed_nonempty_concat(X): + x = X + { List.rev x } +| xs = reversed_nonempty_concat(X) x = X + { List.rev_append x xs } + +(* [nonempty_concat(X)] recognizes a nonempty sequence of [X]s + (each of which is a list), and produces an OCaml list of their concatenation + in direct order -- that is, the first element of the first list in the input + text appears first in the list. +*) + +%inline nonempty_concat(X): + xs = rev(reversed_nonempty_concat(X)) + { xs } + (* [reversed_separated_nonempty_llist(separator, X)] recognizes a nonempty list of [X]s, separated with [separator]s, and produces an OCaml list in reverse order -- that is, the last element in the input text appears first in this @@ -2203,17 +2291,48 @@ class_type_declarations: /* Core expressions */ -seq_expr: - | expr %prec below_SEMI { $1 } - | expr SEMI { $1 } - | mkexp(expr SEMI seq_expr +%inline or_function(EXPR): + | EXPR + { $1 } + | FUNCTION ext_attributes match_cases + { let loc = make_loc $sloc in + let cases = $3 in + (* There are two choices of where to put attributes: on the + Pexp_function node; on the Pfunction_cases body. We put them on the + Pexp_function node here because the compiler only uses + Pfunction_cases attributes for enabling/disabling warnings in + typechecking. For standalone function cases, we want the compiler to + respect, e.g., [@inline] attributes. + *) + let desc = mkfunction [] None (Pfunction_cases (cases, loc, [])) in + mkexp_attrs ~loc:$sloc desc $2 + } +; + +(* [fun_seq_expr] (and [fun_expr]) are legal expression bodies of a function. + [seq_expr] (and [expr]) are expressions that appear in other contexts + (e.g. subexpressions of the expression body of a function). + + [fun_seq_expr] can't be a bare [function _ -> ...]. [seq_expr] can. + + This distinction exists because [function _ -> ...] is parsed as a *function + cases* body of a function, not an expression body. This so functions can be + parsed with the intended arity. +*) +fun_seq_expr: + | fun_expr %prec below_SEMI { $1 } + | fun_expr SEMI { $1 } + | mkexp(fun_expr SEMI seq_expr { Pexp_sequence($1, $3) }) { $1 } - | expr SEMI PERCENT attr_id seq_expr + | fun_expr SEMI PERCENT attr_id seq_expr { let seq = mkexp ~loc:$sloc (Pexp_sequence ($1, $5)) in let payload = PStr [mkstrexp seq []] in mkexp ~loc:$sloc (Pexp_extension ($4, payload)) } ; +seq_expr: + | or_function(fun_seq_expr) { $1 } +; labeled_simple_pattern: QUESTION LPAREN label_let_pattern opt_default RPAREN { (Optional (fst $3), $4, snd $3) } @@ -2284,10 +2403,10 @@ let_pattern: %inline qualified_dotop: ioption(DOT mod_longident {$2}) DOTOP { $1, $2 }; -expr: +fun_expr: simple_expr %prec below_HASH { $1 } - | expr_attrs + | fun_expr_attrs { let desc, attrs = $1 in mkexp_attrs ~loc:$sloc desc attrs } | mkexp(expr_) @@ -2300,7 +2419,7 @@ expr: let pbop_loc = make_loc $sloc in let let_ = {pbop_op; pbop_pat; pbop_exp; pbop_loc} in mkexp ~loc:$sloc (Pexp_letop{ let_; ands; body}) } - | expr COLONCOLON expr + | fun_expr COLONCOLON expr { mkexp_cons ~loc:$sloc $loc($2) (ghexp ~loc:$sloc (Pexp_tuple[$1;$3])) } | mkrhs(label) LESSMINUS expr { mkexp ~loc:$sloc (Pexp_setinstvar($1, $3)) } @@ -2310,7 +2429,7 @@ expr: { mk_indexop_expr builtin_indexing_operators ~loc:$sloc $1 } | indexop_expr(qualified_dotop, expr_semi_list, LESSMINUS v=expr {Some v}) { mk_indexop_expr user_indexing_operators ~loc:$sloc $1 } - | expr attribute + | fun_expr attribute { Exp.attr $1 $2 } /* BEGIN AVOID */ (* Allowed in exprs. Commented-out to reduce diffs with upstream. @@ -2319,7 +2438,10 @@ expr: *) /* END AVOID */ ; -%inline expr_attrs: +%inline expr: + | or_function(fun_expr) { $1 } +; +%inline fun_expr_attrs: | LET MODULE ext_attributes mkrhs(module_name) module_binding_body IN seq_expr { Pexp_letmodule($4, $5, $7), $3 } | LET EXCEPTION ext_attributes let_exception_declaration IN seq_expr @@ -2328,13 +2450,12 @@ expr: { let open_loc = make_loc ($startpos($2), $endpos($5)) in let od = Opn.mk $5 ~override:$3 ~loc:open_loc in Pexp_open(od, $7), $4 } - | FUNCTION ext_attributes match_cases - { Pexp_function $3, $2 } - | FUN ext_attributes labeled_simple_pattern fun_def - { let (l,o,p) = $3 in - Pexp_fun(l, o, p, $4), $2 } - | FUN ext_attributes LPAREN TYPE lident_list RPAREN fun_def - { (mk_newtypes ~loc:$sloc $5 $7).pexp_desc, $2 } + /* Cf #5939: we used to accept (fun p when e0 -> e) */ + | FUN ext_attributes fun_params preceded(COLON, atomic_type)? + MINUSGREATER fun_body + { let body_constraint = Option.map (fun x -> Pconstraint x) $4 in + mkfunction $3 body_constraint $6, $2 + } | MATCH ext_attributes seq_expr WITH match_cases { Pexp_match($3, $5), $2 } | TRY ext_attributes seq_expr WITH match_cases @@ -2370,7 +2491,7 @@ expr: { Pexp_construct($1, Some $2) } | name_tag simple_expr %prec below_HASH { Pexp_variant($1, Some $2) } - | e1 = expr op = op(infix_operator) e2 = expr + | e1 = fun_expr op = op(infix_operator) e2 = expr { mkinfix e1 op e2 } | subtractive expr %prec prec_unary_minus { mkuminus ~oploc:$loc($1) $1 $2 } @@ -2538,10 +2659,9 @@ let_binding_body_no_punning: { let v = $1 in (* PR#7344 *) let t = match $2 with - Some t, None -> + Pconstraint t -> Pvc_constraint { locally_abstract_univars = []; typ=t } - | ground, Some coercion -> Pvc_coercion { ground; coercion} - | _ -> assert false + | Pcoerce (ground, coercion) -> Pvc_coercion { ground; coercion} in (v, $4, Some t) } @@ -2623,19 +2743,26 @@ letop_bindings: let and_ = {pbop_op; pbop_pat; pbop_exp; pbop_loc} in let_pat, let_exp, and_ :: rev_ands } ; -fun_binding: - strict_binding - { $1 } - | type_constraint EQUAL seq_expr - { mkexp_constraint ~loc:$sloc $3 $1 } -; strict_binding: EQUAL seq_expr { $2 } - | labeled_simple_pattern fun_binding - { let (l, o, p) = $1 in ghexp ~loc:$sloc (Pexp_fun(l, o, p, $2)) } - | LPAREN TYPE lident_list RPAREN fun_binding - { mk_newtypes ~loc:$sloc $3 $5 } + | fun_params type_constraint? EQUAL fun_body + { ghexp ~loc:$sloc (mkfunction $1 $2 $4) + } +; +fun_body: + | FUNCTION ext_attributes match_cases + { let ext, attrs = $2 in + match ext with + | None -> Pfunction_cases ($3, make_loc $sloc, attrs) + | Some _ -> + (* function%foo extension nodes interrupt the arity *) + let cases = Pfunction_cases ($3, make_loc $sloc, []) in + Pfunction_body + (mkexp_attrs ~loc:$sloc (mkfunction [] None cases) $2) + } + | fun_seq_expr + { Pfunction_body $1 } ; %inline match_cases: xs = preceded_or_separated_nonempty_llist(BAR, match_case) @@ -2649,20 +2776,28 @@ match_case: | pattern MINUSGREATER DOT { Exp.case $1 (Exp.unreachable ~loc:(make_loc $loc($3)) ()) } ; -fun_def: - MINUSGREATER seq_expr - { $2 } - | mkexp(COLON atomic_type MINUSGREATER seq_expr - { Pexp_constraint ($4, $2) }) - { $1 } -/* Cf #5939: we used to accept (fun p when e0 -> e) */ - | labeled_simple_pattern fun_def - { - let (l,o,p) = $1 in - ghexp ~loc:$sloc (Pexp_fun(l, o, p, $2)) +fun_param_as_list: + | LPAREN TYPE ty_params = lident_list RPAREN + { (* We desugar (type a b c) to (type a) (type b) (type c). + If we do this desugaring, the loc for each parameter is a ghost. + *) + let loc = + match ty_params with + | [] -> assert false (* lident_list is non-empty *) + | [_] -> make_loc $sloc + | _ :: _ :: _ -> ghost_loc $sloc + in + List.map + (fun x -> { pparam_loc = loc; pparam_desc = Pparam_newtype x }) + ty_params + } + | labeled_simple_pattern + { let a, b, c = $1 in + [ { pparam_loc = make_loc $sloc; pparam_desc = Pparam_val (a, b, c) } ] } - | LPAREN TYPE lident_list RPAREN fun_def - { mk_newtypes ~loc:$sloc $3 $5 } +; +fun_params: + | nonempty_concat(fun_param_as_list) { $1 } ; %inline expr_comma_list: es = separated_nontrivial_llist(COMMA, expr) @@ -2709,9 +2844,9 @@ record_expr_content: { es } ; type_constraint: - COLON core_type { (Some $2, None) } - | COLON core_type COLONGREATER core_type { (Some $2, Some $4) } - | COLONGREATER core_type { (None, Some $2) } + COLON core_type { Pconstraint $2 } + | COLON core_type COLONGREATER core_type { Pcoerce (Some $2, $4) } + | COLONGREATER core_type { Pcoerce (None, $2) } | COLON error { syntax_error() } | COLONGREATER error { syntax_error() } ; @@ -3291,8 +3426,8 @@ with_type_binder: /* Polymorphic types */ %inline typevar: - QUOTE mkrhs(ident) - { $2 } + QUOTE ident + { mkrhs $2 $sloc } ; %inline typevar_list: nonempty_llist(typevar) @@ -3346,7 +3481,7 @@ alias_type: function_type { $1 } | mktyp( - ty = alias_type AS QUOTE tyvar = ident + ty = alias_type AS tyvar = typevar { Ptyp_alias(ty, tyvar) } ) { $1 } @@ -3403,44 +3538,100 @@ tuple_type: - applications of type constructors: int, int list, int option list - variant types: [`A] *) + + +(* + Delimited types: + - parenthesised type (type) + - first-class module types (module S) + - object types < x: t; ... > + - variant types [ `A ] + - extension [%foo ...] + + We support local opens on the following classes of types: + - parenthesised + - first-class module types + - variant types + + Object types are not support for local opens due to a potential + conflict with MetaOCaml syntax: + M.< x: t, y: t > + and quoted expressions: + .< e >. + + Extension types are not support for local opens merely as a precaution. +*) +delimited_type_supporting_local_open: + | LPAREN type_ = core_type RPAREN + { type_ } + | LPAREN MODULE attrs = ext_attributes package_type = package_type RPAREN + { wrap_typ_attrs ~loc:$sloc (reloc_typ ~loc:$sloc package_type) attrs } + | mktyp( + LBRACKET field = tag_field RBRACKET + { Ptyp_variant([ field ], Closed, None) } + | LBRACKET BAR fields = row_field_list RBRACKET + { Ptyp_variant(fields, Closed, None) } + | LBRACKET field = row_field BAR fields = row_field_list RBRACKET + { Ptyp_variant(field :: fields, Closed, None) } + | LBRACKETGREATER BAR? fields = row_field_list RBRACKET + { Ptyp_variant(fields, Open, None) } + | LBRACKETGREATER RBRACKET + { Ptyp_variant([], Open, None) } + | LBRACKETLESS BAR? fields = row_field_list RBRACKET + { Ptyp_variant(fields, Closed, Some []) } + | LBRACKETLESS BAR? fields = row_field_list + GREATER + tags = name_tag_list + RBRACKET + { Ptyp_variant(fields, Closed, Some tags) } + ) + { $1 } +; + +object_type: + | mktyp( + LESS meth_list = meth_list GREATER + { let (f, c) = meth_list in Ptyp_object (f, c) } + | LESS GREATER + { Ptyp_object ([], Closed) } + ) + { $1 } +; + +extension_type: + | mktyp ( + ext = extension + { Ptyp_extension ext } + ) + { $1 } +; + +delimited_type: + | object_type + | extension_type + | delimited_type_supporting_local_open + { $1 } +; + atomic_type: - | LPAREN core_type RPAREN - { $2 } - | LPAREN MODULE ext_attributes package_type RPAREN - { wrap_typ_attrs ~loc:$sloc (reloc_typ ~loc:$sloc $4) $3 } + | type_ = delimited_type + { type_ } | mktyp( /* begin mktyp group */ - QUOTE ident - { Ptyp_var $2 } - | UNDERSCORE - { Ptyp_any } - | tys = actual_type_parameters + tys = actual_type_parameters tid = mkrhs(type_longident) - { Ptyp_constr(tid, tys) } - | LESS meth_list GREATER - { let (f, c) = $2 in Ptyp_object (f, c) } - | LESS GREATER - { Ptyp_object ([], Closed) } + { Ptyp_constr (tid, tys) } | tys = actual_type_parameters HASH cid = mkrhs(clty_longident) - { Ptyp_class(cid, tys) } - | LBRACKET tag_field RBRACKET - (* not row_field; see CONFLICTS *) - { Ptyp_variant([$2], Closed, None) } - | LBRACKET BAR row_field_list RBRACKET - { Ptyp_variant($3, Closed, None) } - | LBRACKET row_field BAR row_field_list RBRACKET - { Ptyp_variant($2 :: $4, Closed, None) } - | LBRACKETGREATER BAR? row_field_list RBRACKET - { Ptyp_variant($3, Open, None) } - | LBRACKETGREATER RBRACKET - { Ptyp_variant([], Open, None) } - | LBRACKETLESS BAR? row_field_list RBRACKET - { Ptyp_variant($3, Closed, Some []) } - | LBRACKETLESS BAR? row_field_list GREATER name_tag_list RBRACKET - { Ptyp_variant($3, Closed, Some $5) } - | extension - { Ptyp_extension $1 } + { Ptyp_class (cid, tys) } + | mod_ident = mkrhs(mod_ext_longident) + DOT + type_ = delimited_type_supporting_local_open + { Ptyp_open (mod_ident, type_) } + | QUOTE ident = ident + { Ptyp_var ident } + | UNDERSCORE + { Ptyp_any } ) { $1 } /* end mktyp group */ ; @@ -3459,7 +3650,7 @@ atomic_type: | /* empty */ { [] } | ty = atomic_type - { [ty] } + { [ ty ] } | LPAREN tys = separated_nontrivial_llist(COMMA, core_type) RPAREN { tys } ; @@ -3871,17 +4062,17 @@ attr_id: ) { $1 } ; attribute: - LBRACKETAT attr_id payload RBRACKET - { Attr.mk ~loc:(make_loc $sloc) $2 $3 } + LBRACKETAT attr_id attr_payload RBRACKET + { mk_attr ~loc:(make_loc $sloc) $2 $3 } ; post_item_attribute: - LBRACKETATAT attr_id payload RBRACKET - { Attr.mk ~loc:(make_loc $sloc) $2 $3 } + LBRACKETATAT attr_id attr_payload RBRACKET + { mk_attr ~loc:(make_loc $sloc) $2 $3 } ; floating_attribute: - LBRACKETATATAT attr_id payload RBRACKET + LBRACKETATATAT attr_id attr_payload RBRACKET { mark_symbol_docs $sloc; - Attr.mk ~loc:(make_loc $sloc) $2 $3 } + mk_attr ~loc:(make_loc $sloc) $2 $3 } ; %inline post_item_attributes: post_item_attribute* @@ -3921,4 +4112,10 @@ payload: | QUESTION pattern { PPat ($2, None) } | QUESTION pattern WHEN seq_expr { PPat ($2, Some $4) } ; +attr_payload: + payload + { Builtin_attributes.mark_payload_attrs_used $1; + $1 + } +; %% diff --git a/vendor/parser-standard/parsetree.mli b/vendor/parser-standard/parsetree.mli index fba4d0fc56..b50162c330 100644 --- a/vendor/parser-standard/parsetree.mli +++ b/vendor/parser-standard/parsetree.mli @@ -121,7 +121,7 @@ and core_type_desc = - [T #tconstr] when [l=[T]], - [(T1, ..., Tn) #tconstr] when [l=[T1 ; ... ; Tn]]. *) - | Ptyp_alias of core_type * string (** [T as 'a]. *) + | Ptyp_alias of core_type * string loc (** [T as 'a]. *) | Ptyp_variant of row_field list * closed_flag * label list option (** [Ptyp_variant([`A;`B], flag, labels)] represents: - [[ `A|`B ]] @@ -166,6 +166,7 @@ and core_type_desc = {!value_description}. *) | Ptyp_package of package_type (** [(module S)]. *) + | Ptyp_open of Longident.t loc * core_type (** [M.(T)] *) | Ptyp_extension of extension (** [[%id]]. *) and package_type = Longident.t loc * (Longident.t loc * core_type) list @@ -296,29 +297,20 @@ and expression_desc = - [let rec P1 = E1 and ... and Pn = EN in E] when [flag] is {{!Asttypes.rec_flag.Recursive}[Recursive]}. *) - | Pexp_function of case list (** [function P1 -> E1 | ... | Pn -> En] *) - | Pexp_fun of arg_label * expression option * pattern * expression - (** [Pexp_fun(lbl, exp0, P, E1)] represents: - - [fun P -> E1] - when [lbl] is {{!Asttypes.arg_label.Nolabel}[Nolabel]} - and [exp0] is [None] - - [fun ~l:P -> E1] - when [lbl] is {{!Asttypes.arg_label.Labelled}[Labelled l]} - and [exp0] is [None] - - [fun ?l:P -> E1] - when [lbl] is {{!Asttypes.arg_label.Optional}[Optional l]} - and [exp0] is [None] - - [fun ?l:(P = E0) -> E1] - when [lbl] is {{!Asttypes.arg_label.Optional}[Optional l]} - and [exp0] is [Some E0] - - Notes: - - If [E0] is provided, only - {{!Asttypes.arg_label.Optional}[Optional]} is allowed. - - [fun P1 P2 .. Pn -> E1] is represented as nested - {{!expression_desc.Pexp_fun}[Pexp_fun]}. - - [let f P = E] is represented using - {{!expression_desc.Pexp_fun}[Pexp_fun]}. + | Pexp_function of + function_param list * type_constraint option * function_body + (** [Pexp_function ([P1; ...; Pn], C, body)] represents any construct + involving [fun] or [function], including: + - [fun P1 ... Pn -> E] + when [body = Pfunction_body E] + - [fun P1 ... Pn -> function p1 -> e1 | ... | pm -> em] + when [body = Pfunction_cases [ p1 -> e1; ...; pm -> em ]] + + [C] represents a type constraint or coercion placed immediately before the + arrow, e.g. [fun P1 ... Pn : ty -> ...] when [C = Some (Pconstraint ty)]. + + A function must have parameters. [Pexp_function (params, _, body)] must + have non-empty [params] or a [Pfunction_cases _] body. *) | Pexp_apply of expression * (arg_label * expression) list (** [Pexp_apply(E0, [(l1, E1) ; ... ; (ln, En)])] @@ -441,6 +433,66 @@ and binding_op = pbop_loc : Location.t; } +and function_param_desc = + | Pparam_val of arg_label * expression option * pattern + (** [Pparam_val (lbl, exp0, P)] represents the parameter: + - [P] + when [lbl] is {{!Asttypes.arg_label.Nolabel}[Nolabel]} + and [exp0] is [None] + - [~l:P] + when [lbl] is {{!Asttypes.arg_label.Labelled}[Labelled l]} + and [exp0] is [None] + - [?l:P] + when [lbl] is {{!Asttypes.arg_label.Optional}[Optional l]} + and [exp0] is [None] + - [?l:(P = E0)] + when [lbl] is {{!Asttypes.arg_label.Optional}[Optional l]} + and [exp0] is [Some E0] + + Note: If [E0] is provided, only + {{!Asttypes.arg_label.Optional}[Optional]} is allowed. + *) + | Pparam_newtype of string loc + (** [Pparam_newtype x] represents the parameter [(type x)]. + [x] carries the location of the identifier, whereas the [pparam_loc] + on the enclosing [function_param] node is the location of the [(type x)] + as a whole. + + Multiple parameters [(type a b c)] are represented as multiple + [Pparam_newtype] nodes, let's say: + + {[ [ { pparam_kind = Pparam_newtype a; pparam_loc = loc1 }; + { pparam_kind = Pparam_newtype b; pparam_loc = loc2 }; + { pparam_kind = Pparam_newtype c; pparam_loc = loc3 }; + ] + ]} + + Here, the first loc [loc1] is the location of [(type a b c)], and the + subsequent locs [loc2] and [loc3] are the same as [loc1], except marked as + ghost locations. The locations on [a], [b], [c], correspond to the + variables [a], [b], and [c] in the source code. + *) + +and function_param = + { pparam_loc : Location.t; + pparam_desc : function_param_desc; + } + +and function_body = + | Pfunction_body of expression + | Pfunction_cases of case list * Location.t * attributes + (** In [Pfunction_cases (_, loc, attrs)], the location extends from the + start of the [function] keyword to the end of the last case. The compiler + will only use typechecking-related attributes from [attrs], e.g. enabling + or disabling a warning. + *) +(** See the comment on {{!expression_desc.Pexp_function}[Pexp_function]}. *) + +and type_constraint = + | Pconstraint of core_type + | Pcoerce of core_type option * core_type +(** See the comment on {{!expression_desc.Pexp_function}[Pexp_function]}. *) + (** {2 Value descriptions} *) and value_description = diff --git a/vendor/parser-standard/printast.ml b/vendor/parser-standard/printast.ml index bd59bfc4ae..7718d7d77b 100644 --- a/vendor/parser-standard/printast.ml +++ b/vendor/parser-standard/printast.ml @@ -172,7 +172,7 @@ let rec core_type i ppf x = line i ppf "Ptyp_class %a\n" fmt_longident_loc li; list i core_type ppf l | Ptyp_alias (ct, s) -> - line i ppf "Ptyp_alias \"%s\"\n" s; + line i ppf "Ptyp_alias \"%s\"\n" s.txt; core_type i ppf ct; | Ptyp_poly (sl, ct) -> line i ppf "Ptyp_poly%a\n" typevars sl; @@ -180,6 +180,9 @@ let rec core_type i ppf x = | Ptyp_package (s, l) -> line i ppf "Ptyp_package %a\n" fmt_longident_loc s; list i package_with ppf l; + | Ptyp_open (mod_ident, t) -> + line i ppf "Ptyp_open \"%a\"\n" fmt_longident_loc mod_ident; + core_type i ppf t | Ptyp_extension (s, arg) -> line i ppf "Ptyp_extension \"%s\"\n" s.txt; payload i ppf arg @@ -257,15 +260,11 @@ and expression i ppf x = line i ppf "Pexp_let %a\n" fmt_rec_flag rf; list i value_binding ppf l; expression i ppf e; - | Pexp_function l -> + | Pexp_function (params, c, body) -> line i ppf "Pexp_function\n"; - list i case ppf l; - | Pexp_fun (l, eo, p, e) -> - line i ppf "Pexp_fun\n"; - arg_label i ppf l; - option i expression ppf eo; - pattern i ppf p; - expression i ppf e; + list i function_param ppf params; + option i type_constraint ppf c; + function_body i ppf body | Pexp_apply (e, l) -> line i ppf "Pexp_apply\n"; expression i ppf e; @@ -385,6 +384,36 @@ and expression i ppf x = | Pexp_hole -> line i ppf "Pexp_hole" +and function_param i ppf { pparam_desc = desc; pparam_loc = loc } = + match desc with + | Pparam_val (l, eo, p) -> + line i ppf "Pparam_val %a\n" fmt_location loc; + arg_label (i+1) ppf l; + option (i+1) expression ppf eo; + pattern (i+1) ppf p + | Pparam_newtype ty -> + line i ppf "Pparam_newtype \"%s\" %a\n" ty.txt fmt_location loc + +and function_body i ppf body = + match body with + | Pfunction_body e -> + line i ppf "Pfunction_body\n"; + expression (i+1) ppf e + | Pfunction_cases (cases, loc, attrs) -> + line i ppf "Pfunction_cases %a\n" fmt_location loc; + attributes (i+1) ppf attrs; + list (i+1) case ppf cases + +and type_constraint i ppf constraint_ = + match constraint_ with + | Pconstraint ty -> + line i ppf "Pconstraint\n"; + core_type (i+1) ppf ty + | Pcoerce (ty1, ty2) -> + line i ppf "Pcoerce\n"; + option (i+1) core_type ppf ty1; + core_type (i+1) ppf ty2 + and value_description i ppf x = line i ppf "value_description %a %a\n" fmt_string_loc x.pval_name fmt_location x.pval_loc;