Skip to content

Commit

Permalink
Use type annotations from arguments in let rec (#12315)
Browse files Browse the repository at this point in the history
  • Loading branch information
stedolan committed Jun 21, 2023
1 parent d630b57 commit 5babf9b
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Working version
(Jeremy Yallop, review by Nicolás Ojeda Bär and Gabriel Scherer,
suggestion by Rodolphe Lepigre and John Whitington)

- #12315: Use type annotations from arguments in let rec
(Stephen Dolan, review by Gabriel Scherer)

### Runtime system:

- #10111: Increase the detail of location information for debugging events to
Expand Down
38 changes: 38 additions & 0 deletions testsuite/tests/typing-misc/let_rec_approx.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
(* TEST
expect;
*)

module M = struct type t = A | B end
let rec f () = g A
and g (x : M.t) = f ()
[%%expect{|
module M : sig type t = A | B end
val f : unit -> 'a = <fun>
val g : M.t -> 'a = <fun>
|}]

let rec f () = g 42
and g (x : string) = f ()
[%%expect{|
Line 1, characters 17-19:
1 | let rec f () = g 42
^^
Error: This expression has type "int" but an expression was expected of type
"string"
|}]

let rec opt_error ?(opt : string) () = f ?opt ()
[%%expect{|
Line 1, characters 20-32:
1 | let rec opt_error ?(opt : string) () = f ?opt ()
^^^^^^^^^^^^
Error: This pattern matches values of type "string"
but a pattern was expected which matches values of type "'a option"
|}]

let rec opt_ok_f () = opt_ok_g ~foo:A ()
and opt_ok_g ?(foo : M.t option) () = opt_ok_f ()
[%%expect{|
val opt_ok_f : unit -> 'a = <fun>
val opt_ok_g : ?foo:M.t -> unit -> 'a = <fun>
|}]
11 changes: 9 additions & 2 deletions typing/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2540,11 +2540,18 @@ let rec approx_type env sty =
approx_type env sty
| _ -> newvar ()

let type_pattern_approx env spat =
match spat.ppat_desc with
| Ppat_constraint (_, sty) -> approx_type env sty
| _ -> newvar ()

let rec type_approx env sexp =
match sexp.pexp_desc with
Pexp_let (_, _, e) -> type_approx env e
| Pexp_fun (p, _, _, e) ->
let ty = if is_optional p then type_option (newvar ()) else newvar () in
| Pexp_fun (p, _, spat, e) ->
let ty = type_pattern_approx env spat in
if is_optional p then
unify_pat_types spat.ppat_loc env ty (type_option (newvar ()));
newty (Tarrow(p, ty, type_approx env e, commu_ok))
| Pexp_function ({pc_rhs=e}::_) ->
newty (Tarrow(Nolabel, newvar (), type_approx env e, commu_ok))
Expand Down

0 comments on commit 5babf9b

Please sign in to comment.