@@ -93,9 +93,10 @@ let otherAttrsPure (loc, _) = loc.txt <> "react.component"
93
93
let hasAttrOnBinding { pvb_attributes } = find_opt hasAttr pvb_attributes <> None
94
94
95
95
(* Finds the name of the variable the binding is assigned to, otherwise raises Invalid_argument *)
96
- let getFnName binding =
96
+ let rec getFnName binding =
97
97
match binding with
98
- | { pvb_pat = { ppat_desc = Ppat_var { txt } } } -> txt
98
+ | { ppat_desc = Ppat_var { txt } } -> txt
99
+ | { ppat_desc = Ppat_constraint (pat , _ ) } -> getFnName pat
99
100
| _ -> raise (Invalid_argument " react.component calls cannot be destructured." )
100
101
[@@ raises Invalid_argument ]
101
102
@@ -232,6 +233,44 @@ let makeExternalDecl fnName loc namedArgListWithKeyAndRef namedTypeList =
232
233
(makePropsType ~loc namedTypeList)
233
234
[@@ raises Invalid_argument ]
234
235
236
+ let rec newtypeToVar newtype typ =
237
+ let traverse = newtypeToVar newtype in
238
+ { typ with ptyp_desc =
239
+ match typ.ptyp_desc with
240
+ | Ptyp_constr ({ txt = Lident name } , _ ) when name = newtype -> Ptyp_var newtype
241
+ | Ptyp_constr (ident , args ) -> Ptyp_constr (ident, List. map traverse args)
242
+ | Ptyp_arrow (label , typ , rest ) -> Ptyp_arrow (label, traverse typ, traverse rest)
243
+ | Ptyp_tuple (types ) -> Ptyp_tuple (List. map traverse types)
244
+ | Ptyp_class (ident , args ) -> Ptyp_class (ident, List. map traverse args)
245
+ | Ptyp_alias (typ , alias ) -> Ptyp_alias (traverse typ, alias)
246
+ | Ptyp_poly (vars , rest ) -> Ptyp_poly (vars, traverse rest)
247
+ | Ptyp_variant (fields , flag , labels ) ->
248
+ let fields =
249
+ List. map (function
250
+ | Rtag (label , attrs , flag , args ) -> Rtag (label, attrs, flag, List. map traverse args)
251
+ | Rinherit typ -> Rinherit (traverse typ))
252
+ fields
253
+ in
254
+ Ptyp_variant (fields, flag, labels)
255
+ | Ptyp_object (fields , flag ) ->
256
+ let fields =
257
+ List. map (function
258
+ | Otag (label , attrs , typ ) -> Otag (label, attrs, traverse typ)
259
+ | Oinherit typ -> Oinherit (traverse typ))
260
+ fields
261
+ in
262
+ Ptyp_object (fields, flag)
263
+ | Ptyp_package (ident , substitutions ) ->
264
+ let substitutions =
265
+ List. map
266
+ (fun (ident , typ ) -> (ident, traverse typ))
267
+ substitutions
268
+ in
269
+ Ptyp_package (ident, substitutions)
270
+ | Ptyp_extension _ -> Location. raise_errorf " extensions are not allowed in @react.component definitions"
271
+ | (Ptyp_any | Ptyp_var _ ) as typ -> typ
272
+ }
273
+
235
274
(* TODO: some line number might still be wrong *)
236
275
let jsxMapper () =
237
276
let jsxVersion = ref None in
@@ -334,7 +373,7 @@ let jsxMapper () =
334
373
[@@ raises Invalid_argument ]
335
374
in
336
375
337
- let rec recursivelyTransformNamedArgsForMake mapper expr list =
376
+ let rec recursivelyTransformNamedArgsForMake mapper expr args newtypes =
338
377
let expr = mapper.expr mapper expr in
339
378
match expr.pexp_desc with
340
379
(* TODO: make this show up with a loc. * )
@@ -375,19 +414,23 @@ let jsxMapper () =
375
414
let type_ = match pattern with { ppat_desc = Ppat_constraint (_ , type_ ) } -> Some type_ | _ -> None in
376
415
377
416
recursivelyTransformNamedArgsForMake mapper expression
378
- ((arg, default, pattern, alias, pattern.ppat_loc, type_) :: list )
417
+ ((arg, default, pattern, alias, pattern.ppat_loc, type_) :: args) newtypes
379
418
| Pexp_fun (Nolabel , _ , { ppat_desc = Ppat_construct ({ txt = Lident "()" } , _ ) | Ppat_any } , _expression ) ->
380
- (list , None )
419
+ (args, newtypes , None )
381
420
| Pexp_fun
382
421
( Nolabel ,
383
422
_,
384
423
{ ppat_desc = Ppat_var { txt } | Ppat_constraint ({ ppat_desc = Ppat_var { txt } }, _) },
385
424
_expression ) ->
386
- (list , Some txt)
425
+ (args, newtypes , Some txt)
387
426
| Pexp_fun (Nolabel, _ , pattern , _expression ) ->
388
427
Location. raise_errorf ~loc: pattern.ppat_loc
389
428
" React: react.component refs only support plain arguments and type annotations."
390
- | _ -> (list , None )
429
+ | Pexp_newtype (label , expression ) ->
430
+ recursivelyTransformNamedArgsForMake mapper expression args (label :: newtypes)
431
+ | Pexp_constraint (expression , _typ ) ->
432
+ recursivelyTransformNamedArgsForMake mapper expression args newtypes
433
+ | _ -> (args, newtypes, None )
391
434
[@@ raises Invalid_argument ]
392
435
in
393
436
@@ -487,7 +530,7 @@ let jsxMapper () =
487
530
let bindingLoc = binding.pvb_loc in
488
531
let bindingPatLoc = binding.pvb_pat.ppat_loc in
489
532
let binding = { binding with pvb_pat = { binding.pvb_pat with ppat_loc = emptyLoc }; pvb_loc = emptyLoc } in
490
- let fnName = getFnName binding in
533
+ let fnName = getFnName binding.pvb_pat in
491
534
let internalFnName = fnName ^ " $Internal" in
492
535
let fullModuleName = makeModuleName fileName ! nestedModules fnName in
493
536
let modifiedBindingOld binding =
@@ -496,7 +539,8 @@ let jsxMapper () =
496
539
let rec spelunkForFunExpression expression =
497
540
match expression with
498
541
(* let make = (~prop) => ... *)
499
- | { pexp_desc = Pexp_fun _ } -> expression
542
+ | { pexp_desc = Pexp_fun _ }
543
+ | { pexp_desc = Pexp_newtype _ } -> expression
500
544
(* let make = {let foo = bar in (~prop) => ...} *)
501
545
| { pexp_desc = Pexp_let (_recursive , _vbs , returnExpression ) } ->
502
546
(* here's where we spelunk! *)
@@ -506,6 +550,8 @@ let jsxMapper () =
506
550
spelunkForFunExpression innerFunctionExpression
507
551
| { pexp_desc = Pexp_sequence (_wrapperExpression , innerFunctionExpression ) } ->
508
552
spelunkForFunExpression innerFunctionExpression
553
+ | { pexp_desc = Pexp_constraint (innerFunctionExpression , _typ ) } ->
554
+ spelunkForFunExpression innerFunctionExpression
509
555
| _ ->
510
556
raise
511
557
(Invalid_argument
@@ -594,8 +640,8 @@ let jsxMapper () =
594
640
in
595
641
let props = getPropsAttr payload in
596
642
(* do stuff here! *)
597
- let namedArgList, forwardRef =
598
- recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) []
643
+ let namedArgList, newtypes, forwardRef =
644
+ recursivelyTransformNamedArgsForMake mapper (modifiedBindingOld binding) [] []
599
645
in
600
646
let namedArgListWithKeyAndRef =
601
647
(optional " key" , None , Pat. var { txt = " key" ; loc = emptyLoc }, " key" , emptyLoc, Some (keyType emptyLoc))
@@ -630,7 +676,25 @@ let jsxMapper () =
630
676
in
631
677
let namedTypeList = List. fold_left argToType [] namedArgList in
632
678
let loc = emptyLoc in
633
- let externalDecl = makeExternalDecl fnName loc namedArgListWithKeyAndRef namedTypeList in
679
+ let externalArgs = (* translate newtypes to type variables *)
680
+ List. fold_left
681
+ (fun args newtype ->
682
+ List. map (fun (a , b , c , d , e , maybeTyp ) ->
683
+ match maybeTyp with
684
+ | Some typ -> (a, b, c, d, e, Some (newtypeToVar newtype.txt typ))
685
+ | None -> (a, b, c, d, e, None ))
686
+ args)
687
+ namedArgListWithKeyAndRef
688
+ newtypes
689
+ in
690
+ let externalTypes = (* translate newtypes to type variables *)
691
+ List. fold_left
692
+ (fun args newtype ->
693
+ List. map (fun (a , b , typ ) -> (a, b, newtypeToVar newtype.txt typ)) args)
694
+ namedTypeList
695
+ newtypes
696
+ in
697
+ let externalDecl = makeExternalDecl fnName loc externalArgs externalTypes in
634
698
let innerExpressionArgs =
635
699
List. map pluckArg namedArgListWithKeyAndRefForNew
636
700
@ if hasUnit then [ (Nolabel , Exp. construct { loc; txt = Lident " ()" } None ) ] else []
@@ -660,7 +724,7 @@ let jsxMapper () =
660
724
{
661
725
ppat_desc =
662
726
Ppat_constraint
663
- (makePropsName ~loc: emptyLoc props.propsName, makePropsType ~loc: emptyLoc namedTypeList );
727
+ (makePropsName ~loc: emptyLoc props.propsName, makePropsType ~loc: emptyLoc externalTypes );
664
728
ppat_loc = emptyLoc;
665
729
ppat_attributes = [] ;
666
730
}
0 commit comments