@@ -95,10 +95,14 @@ type error =
9595 | Type_params_not_supported of Longident .t
9696 | Field_access_on_dict_type
9797 | Jsx_not_enabled
98+ | AliasPolyFromLiterals_NonLiteralOrPattern
99+ | AliasPolyFromLiterals_UnsupportedBaseType of type_expr
98100
99101exception Error of Location. t * Env. t * error
100102exception Error_forward of Location. error
101103
104+ module StringSet = Set. Make (String )
105+
102106(* Forward declaration, to be filled in by Typemod.type_module *)
103107
104108let type_module =
@@ -608,6 +612,48 @@ let build_or_pat env loc lid =
608612 in
609613 (path, rp {r with pat_loc = loc}, ty)
610614
615+ let maybe_closed_polyvariant_from_literal_or ~env ~loc ~attrs ~typed_pat
616+ ~base_ty =
617+ let has_attr =
618+ List. exists (function
619+ | {Location. txt = "res.asPolyVariantFromLiterals" } , _ -> true
620+ | _ -> false )
621+ in
622+ if not (has_attr attrs) then None
623+ else
624+ let invalid = ref false in
625+ let rec gather (p : pattern ) (acc : string list ) =
626+ match p.pat_desc with
627+ | Tpat_or (p1 , p2 , _ ) -> gather p2 (gather p1 acc)
628+ | Tpat_constant (Const_string (s , _ )) -> s :: acc
629+ | Tpat_constant (Const_int i ) -> string_of_int i :: acc
630+ | _ ->
631+ invalid := true ;
632+ acc
633+ in
634+ let literals =
635+ gather typed_pat [] |> List. rev |> StringSet. of_list |> StringSet. elements
636+ in
637+ if ! invalid || literals = [] then
638+ raise (Error (loc, env, AliasPolyFromLiterals_NonLiteralOrPattern ))
639+ else
640+ match (repr (expand_head env base_ty)).desc with
641+ | Tconstr (p, [] , _)
642+ when Path. same p Predef. path_string || Path. same p Predef. path_int ->
643+ let row =
644+ {
645+ row_fields = List. map (fun l -> (l, Rpresent None )) literals;
646+ row_more = newvar () ;
647+ row_closed = true ;
648+ row_fixed = false ;
649+ row_name = None ;
650+ }
651+ in
652+ Some (newty (Tvariant row))
653+ | _ ->
654+ raise
655+ (Error (loc, env, AliasPolyFromLiterals_UnsupportedBaseType base_ty))
656+
611657let extract_type_from_pat_variant_spread env lid expected_ty =
612658 let path, decl = Typetexp. find_type env lid.loc lid.txt in
613659 match decl with
@@ -1290,7 +1336,14 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env sp
12901336 let ty_var =
12911337 match override_type_from_variant_spread with
12921338 | Some ty -> ty
1293- | None -> build_as_type ! env q
1339+ | None -> (
1340+ let base_ty = build_as_type ! env q in
1341+ match
1342+ maybe_closed_polyvariant_from_literal_or ~env: ! env ~loc
1343+ ~attrs: sp.ppat_attributes ~typed_pat: q ~base_ty
1344+ with
1345+ | Some ty -> ty
1346+ | None -> base_ty)
12941347 in
12951348 end_def () ;
12961349 generalize ty_var;
@@ -4719,6 +4772,16 @@ let report_error env loc ppf error =
47194772 fprintf ppf
47204773 " Cannot compile JSX expression because JSX support is not enabled. Add \
47214774 \" jsx\" settings to rescript.json to enable JSX support."
4775+ | AliasPolyFromLiterals_NonLiteralOrPattern ->
4776+ fprintf ppf
4777+ " @[The alias form @{<info>as #...id@} can only be used when matching an \
4778+ or-pattern made solely of string or int literals, e.g. \
4779+ @{<info>\" a\" |\" b\" @} or @{<info>1|2@}.@]"
4780+ | AliasPolyFromLiterals_UnsupportedBaseType ty ->
4781+ fprintf ppf
4782+ " @[The alias form @{<info>as #...id@} requires the alias to have type \
4783+ @{<info>string@} or @{<info>int@}, but here it has type@ %a@]"
4784+ type_expr ty
47224785
47234786let report_error env loc ppf err =
47244787 Printtyp. wrap_printing_env env (fun () -> report_error env loc ppf err)
0 commit comments