Skip to content

Commit

Permalink
[typer] be more elaborate about top-down inference of local functions
Browse files Browse the repository at this point in the history
closes #10336

This might be dicey!
  • Loading branch information
Simn committed Feb 17, 2022
1 parent 8bce1a1 commit 936a58b
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 14 deletions.
26 changes: 26 additions & 0 deletions src/core/tUnification.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,32 @@ module UnifyMinT = struct
let common_types = collect_base_types t0 in
unify_min' uctx common_types tl
end

type unification_matrix_state =
| STop
| SType of t
| SBottom

class unification_matrix (arity : int) = object(self)
val values = Array.make arity STop

method join (t : t) (at : int) =
match values.(at) with
| STop ->
values.(at) <- SType t
| SBottom ->
()
| SType t' ->
if not (type_iseq t t') then values.(at) <- SBottom

method get_type (at : int) =
match values.(at) with
| SType t ->
Some t
| _ ->
None
end

;;
unify_ref := unify_custom;;
unify_min_ref := UnifyMinT.unify_min;;
Expand Down
72 changes: 58 additions & 14 deletions src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1197,30 +1197,74 @@ and type_local_function ctx kind f with_type p =
let type_arg _ opt t p = Typeload.load_type_hint ~opt ctx p t in
let args = new FunctionArguments.function_arguments ctx type_arg false ctx.in_display None f.f_args in
let targs = args#for_type in
let maybe_unify_arg t1 t2 =
match follow t1 with
| TMono _ -> unify ctx t2 t1 p
| _ -> ()
in
let maybe_unify_ret tr = match follow tr,follow rt with
| TAbstract({a_path = [],"Void"},_),_ when kind <> FKArrow -> ()
| _,TMono _ -> unify ctx rt tr p
| _ -> ()
in
(* The idea here is: If we have multiple `from Function`, we can
1. ignore any that have a different argument arity, and
2. still top-down infer any argument or return type that is equal across all candidates.
*)
let handle_abstract_matrix l =
let arity = List.length targs in
let m = new unification_matrix (arity + 1) in
let rec loop l = match l with
| t :: l ->
begin match follow t with
| TFun(args,ret) ->
if List.length args = arity then begin
List.iteri (fun i (_,_,t) ->
m#join t (i + 1);
) args;
m#join ret 0;
end;
loop l
| _ ->
raise Exit
end
| [] ->
()
in
begin try
loop l;
List.iteri (fun i (_,_,t1) ->
match m#get_type (i + 1) with
| Some t2 -> maybe_unify_arg t1 t2
| None -> ()
) targs;
begin match m#get_type 0 with
| Some tr ->
maybe_unify_ret tr
| None ->
()
end
with Exit ->
()
end
in
(match with_type with
| WithType.WithType(t,_) ->
let rec loop stack t =
(match follow t with
| TFun (args2,tr) when List.length args2 = List.length targs ->
List.iter2 (fun (_,_,t1) (_,_,t2) ->
match follow t1 with
| TMono _ -> unify ctx t2 t1 p
| _ -> ()
maybe_unify_arg t1 t2
) targs args2;
(* unify for top-down inference unless we are expecting Void *)
begin
match follow tr,follow rt with
| TAbstract({a_path = [],"Void"},_),_ when kind <> FKArrow -> ()
| _,TMono _ -> unify ctx rt tr p
| _ -> ()
end
maybe_unify_ret tr
| TAbstract(a,tl) ->
begin match get_abstract_froms a tl with
| [t2] ->
if not (List.exists (shallow_eq t) stack) then loop (t :: stack) t2
| _ ->
()
end
| [t2] ->
if not (List.exists (shallow_eq t) stack) then loop (t :: stack) t2
| l ->
handle_abstract_matrix l
end
| _ -> ())
in
loop [] t
Expand Down

0 comments on commit 936a58b

Please sign in to comment.