@@ -319,7 +319,7 @@ defmodule Module.Types.Expr do
319
319
else
320
320
clauses
321
321
end
322
- |> of_clauses ( [ case_type ] , expected , expr , info , stack , { none ( ) , context } )
322
+ |> of_clauses ( [ case_type ] , expected , expr , info , stack , context , none ( ) )
323
323
|> dynamic_unless_static ( stack )
324
324
end
325
325
@@ -328,8 +328,20 @@ defmodule Module.Types.Expr do
328
328
[ { :-> , _ , [ head , _ ] } | _ ] = clauses
329
329
{ patterns , _guards } = extract_head ( head )
330
330
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
333
345
end
334
346
335
347
def of_expr ( { :try , _meta , [ [ do: body ] ++ blocks ] } , expected , expr , stack , original ) do
@@ -340,7 +352,7 @@ defmodule Module.Types.Expr do
340
352
if else_block do
341
353
{ type , context } = of_expr ( body , @ pending , body , stack , original )
342
354
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 ( ) )
344
356
else
345
357
of_expr ( body , expected , expr , stack , original )
346
358
end
@@ -364,15 +376,8 @@ defmodule Module.Types.Expr do
364
376
end )
365
377
366
378
{ :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 )
376
381
end )
377
382
|> dynamic_unless_static ( stack )
378
383
@@ -392,8 +397,8 @@ defmodule Module.Types.Expr do
392
397
{ :do , { :__block__ , _ , [ ] } } , acc_context ->
393
398
acc_context
394
399
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 )
397
402
398
403
{ :after , [ { :-> , meta , [ [ timeout ] , body ] } ] = after_expr } , { acc , context } ->
399
404
{ timeout_type , context } = of_expr ( timeout , @ timeout_type , after_expr , stack , context )
@@ -420,7 +425,7 @@ defmodule Module.Types.Expr do
420
425
{ reduce_type , context } = of_expr ( reduce , expected , expr , stack , context )
421
426
# TODO: We need to type check against dynamic() instead of using reduce_type
422
427
# 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 )
424
429
else
425
430
# TODO: Use the collectable protocol for the output
426
431
into = Keyword . get ( opts , :into , [ ] )
@@ -665,7 +670,7 @@ defmodule Module.Types.Expr do
665
670
666
671
defp with_option ( { :else , clauses } , stack , context , _original ) do
667
672
{ _ , 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 ( ) )
669
674
670
675
context
671
676
end
@@ -723,22 +728,27 @@ defmodule Module.Types.Expr do
723
728
defp dynamic_unless_static ( { _ , _ } = output , % { mode: :static } ) , do: output
724
729
defp dynamic_unless_static ( { type , context } , % { mode: _ } ) , do: { dynamic ( type ) , context }
725
730
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
727
743
% { failed: failed? } = original
728
744
729
745
Enum . reduce ( clauses , { acc , original } , fn { :-> , meta , [ head , body ] } , { acc , context } ->
730
746
{ failed? , context } = reset_failed ( context , failed? )
731
747
{ 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 )
733
749
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 ) }
742
752
end )
743
753
end
744
754
@@ -770,6 +780,15 @@ defmodule Module.Types.Expr do
770
780
defp repack_match ( left_expr , right_expr ) ,
771
781
do: { left_expr , right_expr }
772
782
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
+
773
792
## Warning formatting
774
793
775
794
def format_diagnostic ( { :badmap , type , expr , context } ) do
0 commit comments