@@ -278,20 +278,19 @@ defmodule Module.Types.Apply do
278278        { _args_types ,  context }  =  apply_no_domain_args ( args ,  args_fun ,  expr ,  stack ,  context ) 
279279        { dynamic ( ) ,  context } 
280280
281-       in fo  -> 
282-         apply_remote ( info ,  nil ,  name ,  args ,  args_fun ,  expr ,  stack ,  context ) 
283-     end 
284-   end 
281+       { :strong ,  domain ,  clauses }  -> 
282+         domain  =  domain ( domain ,  clauses ) 
283+         { args_types ,  context }  =  apply_args ( args ,  domain ,  [ ] ,  args_fun ,  expr ,  stack ,  context ) 
285284
286-   defp  apply_remote ( info ,  mod ,  fun ,  args ,  args_fun ,  expr ,  stack ,  context )  do 
287-     case  apply_signature ( info ,  args ,  args_fun ,  expr ,  stack ,  context )  do 
288-       { :ok ,  _indexes ,  type ,  context }  -> 
289-         { type ,  context } 
285+         case  apply_strong ( domain ,  clauses ,  args_types ,  stack )  do 
286+           { _used ,  type }  -> 
287+             { type ,  context } 
290288
291-       { :error ,  args_types ,  domain ,  clauses ,  context }  -> 
292-         mfac  =  mfac ( expr ,  mod ,  fun ,  length ( args_types ) ) 
293-         error  =  { { :badremote ,  clauses } ,  domain ,  args_types ,  mfac ,  expr ,  context } 
294-         { error_type ( ) ,  error ( error ,  elem ( expr ,  1 ) ,  stack ,  context ) } 
289+           :error  -> 
290+             mfac  =  mfac ( expr ,  nil ,  name ,  arity ) 
291+             error  =  { { :badremote ,  clauses } ,  domain ,  args_types ,  mfac ,  expr ,  context } 
292+             { error_type ( ) ,  error ( error ,  elem ( expr ,  1 ) ,  stack ,  context ) } 
293+         end 
295294    end 
296295  end 
297296
@@ -375,7 +374,7 @@ defmodule Module.Types.Apply do
375374    { args_types ,  context }  =  apply_args ( args ,  domain ,  [ ] ,  args_fun ,  expr ,  stack ,  context ) 
376375
377376    case  remote_apply ( info ,  args_types ,  stack )  do 
378-       { :ok ,  _indexes ,   type }  -> 
377+       { :ok ,  type }  -> 
379378        { type ,  context } 
380379
381380      { :error ,  error }  -> 
@@ -386,79 +385,61 @@ defmodule Module.Types.Apply do
386385  end 
387386
388387  defp  remote_apply ( :none ,  _args_types ,  _stack )  do 
389-     { :ok ,  [ ] ,   dynamic ( ) } 
388+     { :ok ,  dynamic ( ) } 
390389  end 
391390
392391  defp  remote_apply ( { :infer ,  _domain ,  clauses } ,  args_types ,  _stack )  do 
393-     case  apply_clauses ( clauses ,  args_types ,  0 ,  0 ,  [ ] ,  [ ] )  do 
394-       { 0 ,  [ ] ,  [ ] }  -> 
395-         { :error ,  { :badremote ,  clauses } } 
396- 
397-       { count ,  used ,  _returns }  when  count  >  @ max_clauses  -> 
398-         { :ok ,  used ,  dynamic ( ) } 
399- 
400-       { _count ,  used ,  returns }  -> 
401-         { :ok ,  used ,  returns  |>  Enum . reduce ( & union / 2 )  |>  dynamic ( ) } 
402-     end 
403-   end 
404- 
405-   defp  remote_apply ( { :strong ,  _ ,  [ { expected ,  return } ]  =  clauses } ,  args_types ,  stack )  do 
406-     # Optimize single clauses as the domain is the single clause args. 
407-     case  zip_compatible? ( args_types ,  expected )  do 
408-       true  ->  { :ok ,  [ 0 ] ,  return ( return ,  args_types ,  stack ) } 
409-       false  ->  { :error ,  { :badremote ,  clauses } } 
392+     case  apply_infer ( clauses ,  args_types )  do 
393+       { _used ,  type }  ->  { :ok ,  type } 
394+       :error  ->  { :error ,  { :badremote ,  clauses } } 
410395    end 
411396  end 
412397
413398  defp  remote_apply ( { :strong ,  domain ,  clauses } ,  args_types ,  stack )  do 
414-     # If the type is only gradual, the compatibility check is the same 
415-     # as a non disjoint check. So we skip checking compatibility twice. 
416-     with  true  <-  zip_compatible_or_only_gradual? ( args_types ,  domain ) , 
417-          { count ,  used ,  returns }  when  count  >  0  <-  apply_clauses ( clauses ,  args_types ,  0 ,  0 ,  [ ] ,  [ ] )  do 
418-       { :ok ,  used ,  returns  |>  Enum . reduce ( & union / 2 )  |>  return ( args_types ,  stack ) } 
419-     else 
420-       _  ->  { :error ,  { :badremote ,  clauses } } 
399+     case  apply_strong ( domain ,  clauses ,  args_types ,  stack )  do 
400+       { _used ,  type }  ->  { :ok ,  type } 
401+       :error  ->  { :error ,  { :badremote ,  clauses } } 
421402    end 
422403  end 
423404
424405  defp  remote_apply ( { :element ,  index } ,  [ _index ,  tuple ] ,  _stack )  do 
425406    case  tuple_fetch ( tuple ,  index  -  1 )  do 
426-       { _optional? ,  value_type }  ->  { :ok ,  [ 0 ] ,   value_type } 
407+       { _optional? ,  value_type }  ->  { :ok ,  value_type } 
427408      :badtuple  ->  { :error ,  badremote ( :erlang ,  :element ,  2 ) } 
428409      :badindex  ->  { :error ,  { :badindex ,  index ,  tuple } } 
429410    end 
430411  end 
431412
432413  defp  remote_apply ( { :insert_element ,  index } ,  [ _index ,  tuple ,  value ] ,  _stack )  do 
433414    case  tuple_insert_at ( tuple ,  index  -  1 ,  value )  do 
434-       value_type  when  is_descr ( value_type )  ->  { :ok ,  [ 0 ] ,   value_type } 
415+       value_type  when  is_descr ( value_type )  ->  { :ok ,  value_type } 
435416      :badtuple  ->  { :error ,  badremote ( :erlang ,  :insert_element ,  3 ) } 
436417      :badindex  ->  { :error ,  { :badindex ,  index  -  1 ,  tuple } } 
437418    end 
438419  end 
439420
440421  defp  remote_apply ( { :delete_element ,  index } ,  [ _index ,  tuple ] ,  _stack )  do 
441422    case  tuple_delete_at ( tuple ,  index  -  1 )  do 
442-       value_type  when  is_descr ( value_type )  ->  { :ok ,  [ 0 ] ,   value_type } 
423+       value_type  when  is_descr ( value_type )  ->  { :ok ,  value_type } 
443424      :badtuple  ->  { :error ,  badremote ( :erlang ,  :delete_element ,  2 ) } 
444425      :badindex  ->  { :error ,  { :badindex ,  index ,  tuple } } 
445426    end 
446427  end 
447428
448429  defp  remote_apply ( { :make_tuple ,  size } ,  [ _size ,  elem ] ,  _stack )  do 
449-     { :ok ,  [ 0 ] ,   tuple ( List . duplicate ( elem ,  size ) ) } 
430+     { :ok ,  tuple ( List . duplicate ( elem ,  size ) ) } 
450431  end 
451432
452433  defp  remote_apply ( :hd ,  [ list ] ,  _stack )  do 
453434    case  list_hd ( list )  do 
454-       { _ ,  value_type }  ->  { :ok ,  [ 0 ] ,   value_type } 
435+       { _ ,  value_type }  ->  { :ok ,  value_type } 
455436      :badnonemptylist  ->  { :error ,  badremote ( :erlang ,  :hd ,  1 ) } 
456437    end 
457438  end 
458439
459440  defp  remote_apply ( :tl ,  [ list ] ,  _stack )  do 
460441    case  list_tl ( list )  do 
461-       { _ ,  value_type }  ->  { :ok ,  [ 0 ] ,   value_type } 
442+       { _ ,  value_type }  ->  { :ok ,  value_type } 
462443      :badnonemptylist  ->  { :error ,  badremote ( :erlang ,  :tl ,  1 ) } 
463444    end 
464445  end 
@@ -473,20 +454,20 @@ defmodule Module.Types.Apply do
473454
474455    cond  do 
475456      skip?  -> 
476-         { :ok ,  [ 0 ] ,   result } 
457+         { :ok ,  result } 
477458
478459      match? ( { false ,  _ } ,  map_fetch ( left ,  :__struct__ ) )  or 
479460          match? ( { false ,  _ } ,  map_fetch ( right ,  :__struct__ ) )  -> 
480461        { :error ,  :struct_comparison } 
481462
482463      number_type? ( left )  and  number_type? ( right )  -> 
483-         { :ok ,  [ 0 ] ,   result } 
464+         { :ok ,  result } 
484465
485466      disjoint? ( left ,  right )  -> 
486467        { :error ,  :mismatched_comparison } 
487468
488469      true  -> 
489-         { :ok ,  [ 0 ] ,   result } 
470+         { :ok ,  result } 
490471    end 
491472  end 
492473
@@ -495,16 +476,16 @@ defmodule Module.Types.Apply do
495476
496477    cond  do 
497478      skip?  -> 
498-         { :ok ,  [ 0 ] ,   result } 
479+         { :ok ,  result } 
499480
500481      name  in  [ :== ,  :"/=" ]  and  number_type? ( left )  and  number_type? ( right )  -> 
501-         { :ok ,  [ 0 ] ,   result } 
482+         { :ok ,  result } 
502483
503484      disjoint? ( left ,  right )  -> 
504485        { :error ,  :mismatched_comparison } 
505486
506487      true  -> 
507-         { :ok ,  [ 0 ] ,   result } 
488+         { :ok ,  result } 
508489    end 
509490  end 
510491
@@ -806,6 +787,38 @@ defmodule Module.Types.Apply do
806787    { Enum . reverse ( acc ) ,  context } 
807788  end 
808789
790+   defp  apply_infer ( clauses ,  args_types )  do 
791+     case  apply_clauses ( clauses ,  args_types ,  0 ,  0 ,  [ ] ,  [ ] )  do 
792+       { 0 ,  [ ] ,  [ ] }  -> 
793+         :error 
794+ 
795+       { count ,  used ,  _returns }  when  count  >  @ max_clauses  -> 
796+         { used ,  dynamic ( ) } 
797+ 
798+       { _count ,  used ,  returns }  -> 
799+         { used ,  returns  |>  Enum . reduce ( & union / 2 )  |>  dynamic ( ) } 
800+     end 
801+   end 
802+ 
803+   defp  apply_strong ( _domain ,  [ { expected ,  return } ] ,  args_types ,  stack )  do 
804+     # Optimize single clauses as the domain is the single clause args. 
805+     case  zip_compatible? ( args_types ,  expected )  do 
806+       true  ->  { [ 0 ] ,  return ( return ,  args_types ,  stack ) } 
807+       false  ->  :error 
808+     end 
809+   end 
810+ 
811+   defp  apply_strong ( domain ,  clauses ,  args_types ,  stack )  do 
812+     # If the type is only gradual, the compatibility check is the same 
813+     # as a non disjoint check. So we skip checking compatibility twice. 
814+     with  true  <-  zip_compatible_or_only_gradual? ( args_types ,  domain ) , 
815+          { count ,  used ,  returns }  when  count  >  0  <-  apply_clauses ( clauses ,  args_types ,  0 ,  0 ,  [ ] ,  [ ] )  do 
816+       { used ,  returns  |>  Enum . reduce ( & union / 2 )  |>  return ( args_types ,  stack ) } 
817+     else 
818+       _  ->  :error 
819+     end 
820+   end 
821+ 
809822  defp  apply_clauses ( [ { expected ,  return }  |  clauses ] ,  args_types ,  index ,  count ,  used ,  returns )  do 
810823    if  zip_not_disjoint? ( args_types ,  expected )  do 
811824      apply_clauses ( clauses ,  args_types ,  index  +  1 ,  count  +  1 ,  [ index  |  used ] ,  [ return  |  returns ] ) 
0 commit comments