Skip to content

Commit e657e99

Browse files
lpw25stedolan
authored andcommitted
Relax modes for as patterns (#42)
1 parent f815bf2 commit e657e99

File tree

2 files changed

+191
-40
lines changed

2 files changed

+191
-40
lines changed

testsuite/tests/typing-local/local.ml

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,16 +1448,16 @@ Error: Signature mismatch:
14481448
|}]
14491449

14501450
(* Special handling of tuples in matches and let bindings *)
1451-
let escape : string -> unit = fun x -> ()
1451+
let escape : 'a -> unit = fun x -> ()
14521452

14531453
let foo (local_ x) y =
14541454
match x, y with
14551455
| Some _, Some b -> escape b
14561456
| None, _ -> ()
14571457
| pr -> let _, _ = pr in ();;
14581458
[%%expect{|
1459-
val escape : string -> unit = <fun>
1460-
val foo : local_ 'a option -> string option -> unit = <fun>
1459+
val escape : 'a -> unit = <fun>
1460+
val foo : local_ 'a option -> 'b option -> unit = <fun>
14611461
|}]
14621462

14631463
let foo (local_ x) y =
@@ -1493,7 +1493,7 @@ let foo p (local_ x) y z =
14931493
let _, _ = pr in
14941494
escape b;;
14951495
[%%expect{|
1496-
val foo : bool -> local_ 'a -> string -> 'a * string -> unit = <fun>
1496+
val foo : bool -> local_ 'a -> 'b -> 'a * 'b -> unit = <fun>
14971497
|}]
14981498

14991499
let foo p (local_ x) y (local_ z) =
@@ -1533,6 +1533,115 @@ Line 6, characters 9-10:
15331533
Error: This value escapes its region
15341534
|}]
15351535

1536+
(* [as] patterns *)
1537+
1538+
let foo (local_ x) =
1539+
match x with
1540+
| None as y -> escape y
1541+
| Some _ -> ()
1542+
[%%expect{|
1543+
val foo : local_ 'a option -> unit = <fun>
1544+
|}]
1545+
1546+
let foo (local_ x) =
1547+
match x with
1548+
| None -> ()
1549+
| Some _ as y -> escape y
1550+
[%%expect{|
1551+
Line 4, characters 26-27:
1552+
4 | | Some _ as y -> escape y
1553+
^
1554+
Error: This value escapes its region
1555+
|}]
1556+
1557+
let foo (local_ x) =
1558+
match x with
1559+
| 0 as y -> escape y
1560+
| _ -> ()
1561+
[%%expect{|
1562+
val foo : local_ int -> unit = <fun>
1563+
|}]
1564+
1565+
let foo (local_ x) =
1566+
match x with
1567+
| 'a'..'e' as y -> escape y
1568+
| _ -> ()
1569+
[%%expect{|
1570+
val foo : local_ char -> unit = <fun>
1571+
|}]
1572+
1573+
let foo (local_ x) =
1574+
match x with
1575+
| 1.1 as y -> escape y
1576+
| _ -> ()
1577+
[%%expect{|
1578+
Line 3, characters 23-24:
1579+
3 | | 1.1 as y -> escape y
1580+
^
1581+
Error: This value escapes its region
1582+
|}]
1583+
1584+
let foo (local_ x) =
1585+
match x with
1586+
| `Foo as y -> escape y
1587+
| _ -> ()
1588+
[%%expect{|
1589+
val foo : local_ [> `Foo ] -> unit = <fun>
1590+
|}]
1591+
1592+
let foo (local_ x) =
1593+
match x with
1594+
| (`Foo _) as y -> escape y
1595+
| _ -> ()
1596+
[%%expect{|
1597+
Line 3, characters 28-29:
1598+
3 | | (`Foo _) as y -> escape y
1599+
^
1600+
Error: This value escapes its region
1601+
|}]
1602+
1603+
let foo (local_ x) =
1604+
match x with
1605+
| (None | Some _) as y -> escape y
1606+
[%%expect{|
1607+
Line 3, characters 35-36:
1608+
3 | | (None | Some _) as y -> escape y
1609+
^
1610+
Error: This value escapes its region
1611+
|}]
1612+
1613+
let foo (local_ x) =
1614+
match x with
1615+
| (Some _|None) as y -> escape y
1616+
[%%expect{|
1617+
Line 3, characters 33-34:
1618+
3 | | (Some _|None) as y -> escape y
1619+
^
1620+
Error: This value escapes its region
1621+
|}]
1622+
1623+
type foo = [`Foo | `Bar]
1624+
1625+
let foo (local_ x) =
1626+
match x with
1627+
| #foo as y -> escape y
1628+
[%%expect{|
1629+
type foo = [ `Bar | `Foo ]
1630+
val foo : local_ [< foo ] -> unit = <fun>
1631+
|}]
1632+
1633+
type foo = [`Foo | `Bar of int]
1634+
1635+
let foo (local_ x) =
1636+
match x with
1637+
| #foo as y -> escape y
1638+
[%%expect{|
1639+
type foo = [ `Bar of int | `Foo ]
1640+
Line 5, characters 24-25:
1641+
5 | | #foo as y -> escape y
1642+
^
1643+
Error: This value escapes its region
1644+
|}]
15361645

15371646
(* In debug mode, Gc.minor () checks for minor heap->local pointers *)
15381647
let () = Gc.minor ()

typing/typecore.ml

Lines changed: 78 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -611,44 +611,65 @@ let enter_orpat_variables loc env p1_vs p2_vs =
611611
raise (Error (loc, env, err)) in
612612
unify_vars p1_vs p2_vs
613613

614-
let rec build_as_type env p =
615-
let as_ty = build_as_type_aux env p in
616-
(* Cf. #1655 *)
617-
List.fold_left (fun as_ty (extra, _loc, _attrs) ->
618-
match extra with
619-
| Tpat_type _ | Tpat_open _ | Tpat_unpack -> as_ty
620-
| Tpat_constraint cty ->
621-
begin_def ();
622-
let ty = instance cty.ctyp_type in
623-
end_def ();
624-
generalize_structure ty;
625-
(* This call to unify can't fail since the pattern is well typed. *)
626-
unify !env (instance as_ty) (instance ty);
627-
ty
628-
) as_ty p.pat_extra
614+
let rec build_as_type_and_mode env p =
615+
let as_ty, as_mode = build_as_type_aux env p in
616+
let as_ty =
617+
(* Cf. #1655 *)
618+
List.fold_left (fun as_ty (extra, _loc, _attrs) ->
619+
match extra with
620+
| Tpat_type _ | Tpat_open _ | Tpat_unpack -> as_ty
621+
| Tpat_constraint cty ->
622+
begin_def ();
623+
let ty = instance cty.ctyp_type in
624+
end_def ();
625+
generalize_structure ty;
626+
(* This call to unify can't fail since the pattern is well typed. *)
627+
unify !env (instance as_ty) (instance ty);
628+
ty
629+
) as_ty p.pat_extra
630+
in
631+
as_ty, as_mode
632+
633+
and build_as_type env p =
634+
fst (build_as_type_and_mode env p)
629635

630636
and build_as_type_aux env p =
631637
match p.pat_desc with
632-
Tpat_alias(p1,_, _) -> build_as_type env p1
638+
Tpat_alias(p1,_, _) -> build_as_type_and_mode env p1
633639
| Tpat_tuple pl ->
634640
let tyl = List.map (build_as_type env) pl in
635-
newty (Ttuple tyl)
641+
newty (Ttuple tyl), p.pat_mode
636642
| Tpat_construct(_, cstr, pl) ->
637-
let keep = cstr.cstr_private = Private || cstr.cstr_existentials <> [] in
638-
if keep then p.pat_type else
639-
let tyl = List.map (build_as_type env) pl in
640-
let ty_args, ty_res = instance_constructor cstr in
641-
List.iter2 (fun (p,ty) -> unify_pat env {p with pat_type = ty})
642-
(List.combine pl tyl) ty_args;
643-
ty_res
643+
let priv = (cstr.cstr_private = Private) in
644+
let mode =
645+
if priv || pl <> [] then p.pat_mode
646+
else Value_mode.newvar ()
647+
in
648+
let keep = priv || cstr.cstr_existentials <> [] in
649+
let ty =
650+
if keep then p.pat_type else
651+
let tyl = List.map (build_as_type env) pl in
652+
let ty_args, ty_res = instance_constructor cstr in
653+
List.iter2 (fun (p,ty) -> unify_pat env {p with pat_type = ty})
654+
(List.combine pl tyl) ty_args;
655+
ty_res
656+
in
657+
ty, mode
644658
| Tpat_variant(l, p', _) ->
645659
let ty = Option.map (build_as_type env) p' in
646-
newty (Tvariant{row_fields=[l, Rpresent ty]; row_more=newvar();
647-
row_bound=(); row_name=None;
648-
row_fixed=None; row_closed=false})
660+
let mode =
661+
if p' = None then Value_mode.newvar ()
662+
else p.pat_mode
663+
in
664+
let ty =
665+
newty (Tvariant{row_fields=[l, Rpresent ty]; row_more=newvar();
666+
row_bound=(); row_name=None;
667+
row_fixed=None; row_closed=false})
668+
in
669+
ty, mode
649670
| Tpat_record (lpl,_) ->
650671
let lbl = snd3 (List.hd lpl) in
651-
if lbl.lbl_private = Private then p.pat_type else
672+
if lbl.lbl_private = Private then p.pat_type, p.pat_mode else
652673
let ty = newvar () in
653674
let ppl = List.map (fun (_, l, p) -> l.lbl_pos, p) lpl in
654675
let do_label lbl =
@@ -666,19 +687,40 @@ and build_as_type_aux env p =
666687
unify_pat env p ty_res'
667688
end in
668689
Array.iter do_label lbl.lbl_all;
669-
ty
690+
ty, p.pat_mode
670691
| Tpat_or(p1, p2, row) ->
671692
begin match row with
672693
None ->
673-
let ty1 = build_as_type env p1 and ty2 = build_as_type env p2 in
694+
let ty1, mode1 = build_as_type_and_mode env p1 in
695+
let ty2, mode2 = build_as_type_and_mode env p2 in
674696
unify_pat env {p2 with pat_type = ty2} ty1;
675-
ty1
697+
ty1, Value_mode.join [mode1; mode2]
676698
| Some row ->
677699
let row = row_repr row in
678-
newty (Tvariant{row with row_closed=false; row_more=newvar()})
700+
let all_constant =
701+
List.for_all
702+
(function
703+
| _, (Rpresent (Some _) | Reither (false, _, _, _)) -> false
704+
| _ -> true)
705+
row.row_fields
706+
in
707+
let mode =
708+
if all_constant then Value_mode.newvar ()
709+
else p.pat_mode
710+
in
711+
let ty =
712+
newty (Tvariant{row with row_closed=false; row_more=newvar()})
713+
in
714+
ty, mode
679715
end
680-
| Tpat_any | Tpat_var _ | Tpat_constant _
681-
| Tpat_array _ | Tpat_lazy _ -> p.pat_type
716+
| Tpat_constant _ ->
717+
let mode =
718+
if Ctype.maybe_pointer_type !env p.pat_type then p.pat_mode
719+
else Value_mode.newvar ()
720+
in
721+
p.pat_type, mode
722+
| Tpat_any | Tpat_var _
723+
| Tpat_array _ | Tpat_lazy _ -> p.pat_type, p.pat_mode
682724

683725
let build_or_pat env loc mode lid =
684726
let path, decl = Env.lookup_type ~loc:lid.loc lid.txt env in
@@ -1623,11 +1665,11 @@ and type_pat_aux
16231665
assert construction_not_used_in_counterexamples;
16241666
type_pat Value sq expected_ty (fun q ->
16251667
begin_def ();
1626-
let ty_var = build_as_type env q in
1668+
let ty_var, mode = build_as_type_and_mode env q in
16271669
end_def ();
16281670
generalize ty_var;
16291671
let id =
1630-
enter_variable ~is_as_variable:true loc name alloc_mode.mode
1672+
enter_variable ~is_as_variable:true loc name mode
16311673
ty_var sp.ppat_attributes
16321674
in
16331675
rvp k {

0 commit comments

Comments
 (0)