@@ -319,7 +319,7 @@ defmodule Module.Types.Expr do
319319    else 
320320      clauses 
321321    end 
322-     |>  of_clauses ( [ case_type ] ,  expected ,  expr ,  info ,  stack ,  { none ( ) ,   context } ) 
322+     |>  of_clauses ( [ case_type ] ,  expected ,  expr ,  info ,  stack ,  context ,   none ( ) ) 
323323    |>  dynamic_unless_static ( stack ) 
324324  end 
325325
@@ -328,8 +328,20 @@ defmodule Module.Types.Expr do
328328    [ { :-> ,  _ ,  [ head ,  _ ] }  |  _ ]  =  clauses 
329329    { patterns ,  _guards }  =  extract_head ( head ) 
330330    domain  =  Enum . map ( patterns ,  fn  _  ->  dynamic ( )  end ) 
331-     { _acc ,  context }  =  of_clauses ( clauses ,  domain ,  @ pending ,  nil ,  :fn ,  stack ,  { none ( ) ,  context } ) 
332-     { dynamic ( fun ( length ( patterns ) ) ) ,  context } 
331+ 
332+     if  stack . mode  ==  :traversal  do 
333+       { _acc ,  context }  =  of_clauses ( clauses ,  domain ,  @ pending ,  nil ,  :fn ,  stack ,  context ,  none ( ) ) 
334+       { dynamic ( fun ( length ( patterns ) ) ) ,  context } 
335+     else 
336+       { acc ,  context }  = 
337+         of_clauses_fun ( clauses ,  domain ,  @ pending ,  nil ,  :fn ,  stack ,  context ,  [ ] ,  fn 
338+           trees ,  body ,  context ,  acc  -> 
339+             args  =  Pattern . of_domain ( trees ,  domain ,  context ) 
340+             add_inferred ( acc ,  args ,  body ) 
341+         end ) 
342+ 
343+       { fun_from_overlapping_clauses ( acc ) ,  context } 
344+     end 
333345  end 
334346
335347  def  of_expr ( { :try ,  _meta ,  [ [ do:  body ]  ++  blocks ] } ,  expected ,  expr ,  stack ,  original )  do 
@@ -340,7 +352,7 @@ defmodule Module.Types.Expr do
340352      if  else_block  do 
341353        { type ,  context }  =  of_expr ( body ,  @ pending ,  body ,  stack ,  original ) 
342354        info  =  { :try_else ,  type } 
343-         of_clauses ( else_block ,  [ type ] ,  expected ,  expr ,  info ,  stack ,  { none ( ) ,   context } ) 
355+         of_clauses ( else_block ,  [ type ] ,  expected ,  expr ,  info ,  stack ,  context ,   none ( ) ) 
344356      else 
345357        of_expr ( body ,  expected ,  expr ,  stack ,  original ) 
346358      end 
@@ -364,15 +376,8 @@ defmodule Module.Types.Expr do
364376          end ) 
365377
366378        { :catch ,  clauses } ,  { acc ,  context }  -> 
367-           of_clauses ( 
368-             clauses , 
369-             [ @ try_catch ,  dynamic ( ) ] , 
370-             expected , 
371-             expr , 
372-             :try_catch , 
373-             stack , 
374-             { acc ,  context } 
375-           ) 
379+           args  =  [ @ try_catch ,  dynamic ( ) ] 
380+           of_clauses ( clauses ,  args ,  expected ,  expr ,  :try_catch ,  stack ,  context ,  acc ) 
376381      end ) 
377382      |>  dynamic_unless_static ( stack ) 
378383
@@ -392,8 +397,8 @@ defmodule Module.Types.Expr do
392397      { :do ,  { :__block__ ,  _ ,  [ ] } } ,  acc_context  -> 
393398        acc_context 
394399
395-       { :do ,  clauses } ,  acc_context  -> 
396-         of_clauses ( clauses ,  [ dynamic ( ) ] ,  expected ,  expr ,  :receive ,  stack ,  acc_context ) 
400+       { :do ,  clauses } ,  { acc ,   context }  -> 
401+         of_clauses ( clauses ,  [ dynamic ( ) ] ,  expected ,  expr ,  :receive ,  stack ,  context ,   acc ) 
397402
398403      { :after ,  [ { :-> ,  meta ,  [ [ timeout ] ,  body ] } ]  =  after_expr } ,  { acc ,  context }  -> 
399404        { timeout_type ,  context }  =  of_expr ( timeout ,  @ timeout_type ,  after_expr ,  stack ,  context ) 
@@ -420,7 +425,7 @@ defmodule Module.Types.Expr do
420425      { reduce_type ,  context }  =  of_expr ( reduce ,  expected ,  expr ,  stack ,  context ) 
421426      # TODO: We need to type check against dynamic() instead of using reduce_type 
422427      # because this is recursive. We need to infer the block type first. 
423-       of_clauses ( block ,  [ dynamic ( ) ] ,  expected ,  expr ,  :for_reduce ,  stack ,  { reduce_type ,   context } ) 
428+       of_clauses ( block ,  [ dynamic ( ) ] ,  expected ,  expr ,  :for_reduce ,  stack ,  context ,   reduce_type ) 
424429    else 
425430      # TODO: Use the collectable protocol for the output 
426431      into  =  Keyword . get ( opts ,  :into ,  [ ] ) 
@@ -665,7 +670,7 @@ defmodule Module.Types.Expr do
665670
666671  defp  with_option ( { :else ,  clauses } ,  stack ,  context ,  _original )  do 
667672    { _ ,  context }  = 
668-       of_clauses ( clauses ,  [ dynamic ( ) ] ,  @ pending ,  nil ,  :with_else ,  stack ,  { none ( ) ,   context } ) 
673+       of_clauses ( clauses ,  [ dynamic ( ) ] ,  @ pending ,  nil ,  :with_else ,  stack ,  context ,   none ( ) ) 
669674
670675    context 
671676  end 
@@ -723,22 +728,27 @@ defmodule Module.Types.Expr do
723728  defp  dynamic_unless_static ( { _ ,  _ }  =  output ,  % { mode:  :static } ) ,  do:  output 
724729  defp  dynamic_unless_static ( { type ,  context } ,  % { mode:  _ } ) ,  do:  { dynamic ( type ) ,  context } 
725730
726-   defp  of_clauses ( clauses ,  domain ,  expected ,  expr ,  info ,  % { mode:  mode }  =  stack ,  { acc ,  original } )  do 
731+   defp  of_clauses ( clauses ,  domain ,  expected ,  expr ,  info ,  % { mode:  mode }  =  stack ,  context ,  acc )  do 
732+     fun  = 
733+       if  mode  ==  :traversal  do 
734+         fn  _ ,  _ ,  _ ,  _  ->  dynamic ( )  end 
735+       else 
736+         fn  _trees ,  result ,  _context ,  acc  ->  union ( result ,  acc )  end 
737+       end 
738+ 
739+     of_clauses_fun ( clauses ,  domain ,  expected ,  expr ,  info ,  stack ,  context ,  acc ,  fun ) 
740+   end 
741+ 
742+   defp  of_clauses_fun ( clauses ,  domain ,  expected ,  expr ,  info ,  stack ,  original ,  acc ,  fun )  do 
727743    % { failed:  failed? }  =  original 
728744
729745    Enum . reduce ( clauses ,  { acc ,  original } ,  fn  { :-> ,  meta ,  [ head ,  body ] } ,  { acc ,  context }  -> 
730746      { failed? ,  context }  =  reset_failed ( context ,  failed? ) 
731747      { patterns ,  guards }  =  extract_head ( head ) 
732-       { _trees ,  context }  =  Pattern . of_head ( patterns ,  guards ,  domain ,  info ,  meta ,  stack ,  context ) 
748+       { trees ,  context }  =  Pattern . of_head ( patterns ,  guards ,  domain ,  info ,  meta ,  stack ,  context ) 
733749
734-       { body ,  context }  =  of_expr ( body ,  expected ,  expr  ||  body ,  stack ,  context ) 
735-       context  =  context  |>  set_failed ( failed? )  |>  reset_vars ( original ) 
736- 
737-       if  mode  ==  :traversal  do 
738-         { dynamic ( ) ,  context } 
739-       else 
740-         { union ( acc ,  body ) ,  context } 
741-       end 
750+       { result ,  context }  =  of_expr ( body ,  expected ,  expr  ||  body ,  stack ,  context ) 
751+       { fun . ( trees ,  result ,  context ,  acc ) ,  context  |>  set_failed ( failed? )  |>  reset_vars ( original ) } 
742752    end ) 
743753  end 
744754
@@ -770,6 +780,15 @@ defmodule Module.Types.Expr do
770780  defp  repack_match ( left_expr ,  right_expr ) , 
771781    do:  { left_expr ,  right_expr } 
772782
783+   defp  add_inferred ( [ { args ,  existing_return }  |  tail ] ,  args ,  return ) , 
784+     do:  [ { args ,  union ( existing_return ,  return ) }  |  tail ] 
785+ 
786+   defp  add_inferred ( [ head  |  tail ] ,  args ,  return ) , 
787+     do:  [ head  |  add_inferred ( tail ,  args ,  return ) ] 
788+ 
789+   defp  add_inferred ( [ ] ,  args ,  return ) , 
790+     do:  [ { args ,  return } ] 
791+ 
773792  ## Warning formatting 
774793
775794  def  format_diagnostic ( { :badmap ,  type ,  expr ,  context } )  do 
0 commit comments