@@ -472,8 +472,6 @@ defmodule Module.Types.Apply do
472
472
Returns the type of a remote capture.
473
473
"""
474
474
def remote_capture ( modules , fun , arity , meta , stack , context ) do
475
- # TODO: Do we check when the union of functions is invalid?
476
- # TODO: Deal with :infer types
477
475
if stack . mode == :traversal or modules == [ ] do
478
476
{ dynamic ( fun ( arity ) ) , context }
479
477
else
@@ -483,6 +481,9 @@ defmodule Module.Types.Apply do
483
481
{ { :strong , _ , clauses } , context } ->
484
482
{ union ( type , fun_from_non_overlapping_clauses ( clauses ) ) , fallback? , context }
485
483
484
+ { { :infer , _ , clauses } , context } when length ( clauses ) <= @ max_clauses ->
485
+ { union ( type , fun_from_overlapping_clauses ( clauses ) ) , fallback? , context }
486
+
486
487
{ _ , context } ->
487
488
{ type , true , context }
488
489
end
@@ -610,6 +611,19 @@ defmodule Module.Types.Apply do
610
611
not Enum . any? ( stack . no_warn_undefined , & ( & 1 == module or & 1 == { module , fun , arity } ) )
611
612
end
612
613
614
+ ## Funs
615
+
616
+ def fun_apply ( fun_type , args_types , call , stack , context ) do
617
+ case fun_apply ( fun_type , args_types ) do
618
+ { :ok , res } ->
619
+ { res , context }
620
+
621
+ reason ->
622
+ error = { { :badapply , reason } , args_types , fun_type , call , context }
623
+ { error_type ( ) , error ( __MODULE__ , error , elem ( call , 1 ) , stack , context ) }
624
+ end
625
+ end
626
+
613
627
## Local
614
628
615
629
def local_domain ( fun , args , expected , meta , stack , context ) do
@@ -682,13 +696,25 @@ defmodule Module.Types.Apply do
682
696
{ _kind , _info , context } when stack . mode == :traversal ->
683
697
{ dynamic ( fun ( arity ) ) , context }
684
698
685
- { kind , _info , context } ->
686
- if stack . mode != :infer and kind == :defp do
687
- # Mark all clauses as used, as the function is being exported.
688
- { dynamic ( fun ( arity ) ) , put_in ( context . local_used [ fun_arity ] , [ ] ) }
689
- else
690
- { dynamic ( fun ( arity ) ) , context }
691
- end
699
+ { kind , info , context } ->
700
+ result =
701
+ case info do
702
+ { :infer , _ , clauses } when length ( clauses ) <= @ max_clauses ->
703
+ fun_from_overlapping_clauses ( clauses )
704
+
705
+ _ ->
706
+ dynamic ( fun ( arity ) )
707
+ end
708
+
709
+ context =
710
+ if stack . mode != :infer and kind == :defp do
711
+ # Mark all clauses as used, as the function is being exported.
712
+ put_in ( context . local_used [ fun_arity ] , [ ] )
713
+ else
714
+ context
715
+ end
716
+
717
+ { result , context }
692
718
end
693
719
end
694
720
@@ -805,6 +831,78 @@ defmodule Module.Types.Apply do
805
831
806
832
## Diagnostics
807
833
834
+ def format_diagnostic ( { { :badapply , reason } , args_types , fun_type , expr , context } ) do
835
+ traces =
836
+ case reason do
837
+ # Include arguments in traces in case of badarg
838
+ { :badarg , _ } -> collect_traces ( expr , context )
839
+ # Otherwise just the fun
840
+ _ -> collect_traces ( elem ( expr , 0 ) , context )
841
+ end
842
+
843
+ message =
844
+ case reason do
845
+ { :badarg , domain } ->
846
+ """
847
+ incompatible types given on function application:
848
+
849
+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
850
+
851
+ given types:
852
+
853
+ #{ args_to_quoted_string ( args_types , domain , & Function . identity / 1 ) |> indent ( 4 ) }
854
+
855
+ but function has type:
856
+
857
+ #{ to_quoted_string ( fun_type ) |> indent ( 4 ) }
858
+ """
859
+
860
+ :badarg ->
861
+ """
862
+ expected a #{ length ( args_types ) } -arity function on call:
863
+
864
+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
865
+
866
+ but got type:
867
+
868
+ #{ to_quoted_string ( fun_type ) |> indent ( 4 ) }
869
+ """
870
+
871
+ { :badarity , arities } ->
872
+ info =
873
+ case arities do
874
+ [ arity ] -> "function with arity #{ arity } "
875
+ _ -> "function with arities #{ Enum . join ( arities , "," ) } "
876
+ end
877
+
878
+ """
879
+ expected a #{ length ( args_types ) } -arity function on call:
880
+
881
+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
882
+
883
+ but got #{ info } :
884
+
885
+ #{ to_quoted_string ( fun_type ) |> indent ( 4 ) }
886
+ """
887
+
888
+ :badfun ->
889
+ """
890
+ expected a #{ length ( args_types ) } -arity function on call:
891
+
892
+ #{ expr_to_string ( expr ) |> indent ( 4 ) }
893
+
894
+ but got type:
895
+
896
+ #{ to_quoted_string ( fun_type ) |> indent ( 4 ) }
897
+ """
898
+ end
899
+
900
+ % {
901
+ details: % { typing_traces: traces } ,
902
+ message: IO . iodata_to_binary ( [ message , format_traces ( traces ) ] )
903
+ }
904
+ end
905
+
808
906
def format_diagnostic ( { :badlocal , { _ , domain , clauses } , args_types , expr , context } ) do
809
907
domain = domain ( domain , clauses )
810
908
traces = collect_traces ( expr , context )
0 commit comments