@@ -472,8 +472,6 @@ defmodule Module.Types.Apply do
472472 Returns the type of a remote capture.
473473 """
474474 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
477475 if stack . mode == :traversal or modules == [ ] do
478476 { dynamic ( fun ( arity ) ) , context }
479477 else
@@ -483,6 +481,9 @@ defmodule Module.Types.Apply do
483481 { { :strong , _ , clauses } , context } ->
484482 { union ( type , fun_from_non_overlapping_clauses ( clauses ) ) , fallback? , context }
485483
484+ { { :infer , _ , clauses } , context } when length ( clauses ) <= @ max_clauses ->
485+ { union ( type , fun_from_overlapping_clauses ( clauses ) ) , fallback? , context }
486+
486487 { _ , context } ->
487488 { type , true , context }
488489 end
@@ -610,6 +611,19 @@ defmodule Module.Types.Apply do
610611 not Enum . any? ( stack . no_warn_undefined , & ( & 1 == module or & 1 == { module , fun , arity } ) )
611612 end
612613
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+
613627 ## Local
614628
615629 def local_domain ( fun , args , expected , meta , stack , context ) do
@@ -682,13 +696,25 @@ defmodule Module.Types.Apply do
682696 { _kind , _info , context } when stack . mode == :traversal ->
683697 { dynamic ( fun ( arity ) ) , context }
684698
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 }
692718 end
693719 end
694720
@@ -805,6 +831,78 @@ defmodule Module.Types.Apply do
805831
806832 ## Diagnostics
807833
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+
808906 def format_diagnostic ( { :badlocal , { _ , domain , clauses } , args_types , expr , context } ) do
809907 domain = domain ( domain , clauses )
810908 traces = collect_traces ( expr , context )
0 commit comments