@@ -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