@@ -422,6 +422,17 @@ defmodule Kernel.Typespec do
422
422
{ :{} , [ line: line ] , args }
423
423
end
424
424
425
+ defp typespec_to_ast ( { :type , _line , :list , [ arg ] } ) do
426
+ case unpack_typespec_kw ( arg , [ ] ) do
427
+ { :ok , ast } -> ast
428
+ :error -> [ typespec_to_ast ( arg ) ]
429
+ end
430
+ end
431
+
432
+ defp typespec_to_ast ( { :type , _line , :list , args } ) do
433
+ lc arg inlist args , do: typespec_to_ast ( arg )
434
+ end
435
+
425
436
defp typespec_to_ast ( { :type , line , :binary , [ arg1 , arg2 ] } ) do
426
437
[ arg1 , arg2 ] = lc arg inlist [ arg1 , arg2 ] , do: typespec_to_ast ( arg )
427
438
cond do
@@ -473,7 +484,7 @@ defmodule Kernel.Typespec do
473
484
{ var , line , nil }
474
485
end
475
486
476
- # special shortcut(s)
487
+ # Special shortcut(s)
477
488
defp typespec_to_ast ( { :remote_type , line , [ { :atom , _ , :elixir } , { :atom , _ , :char_list } , [ ] ] } ) do
478
489
typespec_to_ast ( { :type , line , :char_list , [ ] } )
479
490
end
@@ -482,7 +493,6 @@ defmodule Kernel.Typespec do
482
493
typespec_to_ast ( { :type , line , :as_boolean , [ arg ] } )
483
494
end
484
495
485
-
486
496
defp typespec_to_ast ( { :remote_type , line , [ mod , name , args ] } ) do
487
497
args = lc arg inlist args , do: typespec_to_ast ( arg )
488
498
dot = { :. , [ line: line ] , [ typespec_to_ast ( mod ) , typespec_to_ast ( name ) ] }
@@ -524,7 +534,7 @@ defmodule Kernel.Typespec do
524
534
525
535
# Handle unions
526
536
defp typespec ( { :| , meta , [ _ , _ ] } = exprs , vars , caller ) do
527
- exprs = :lists . reverse ( collect_union ( exprs ) )
537
+ exprs = Enum . reverse ( collect_union ( exprs ) )
528
538
union = lc e inlist exprs , do: typespec ( e , vars , caller )
529
539
{ :type , line ( meta ) , :union , union }
530
540
end
@@ -558,7 +568,6 @@ defmodule Kernel.Typespec do
558
568
end
559
569
560
570
# Handle funs
561
-
562
571
defp typespec ( { :-> , meta , [ { [ { :fun , _ , arguments } ] , return } ] } , vars , caller ) when is_list ( arguments ) do
563
572
typespec ( { :-> , meta , [ { arguments , return } ] } , vars , caller )
564
573
end
@@ -609,7 +618,6 @@ defmodule Kernel.Typespec do
609
618
end
610
619
611
620
# Handle blocks
612
-
613
621
defp typespec ( { :__block__ , _meta , [ arg ] } , vars , caller ) do
614
622
typespec ( arg , vars , caller )
615
623
end
@@ -665,8 +673,11 @@ defmodule Kernel.Typespec do
665
673
typespec ( { :nonempty_list , [ ] , [ spec ] } , vars , caller )
666
674
end
667
675
668
- defp typespec ( l , _ , _ ) when is_list ( l ) do
669
- raise ArgumentError , message: "Unexpected list #{ inspect l } "
676
+ defp typespec ( [ h | t ] = l , vars , caller ) do
677
+ union = Enum . reduce ( t , validate_kw ( h , l ) , fn ( x , acc ) ->
678
+ { :| , [ ] , [ acc , validate_kw ( x , l ) ] }
679
+ end )
680
+ typespec ( { :list , [ ] , [ union ] } , vars , caller )
670
681
end
671
682
672
683
defp typespec ( t , vars , caller ) when is_tuple ( t ) do
@@ -684,6 +695,11 @@ defmodule Kernel.Typespec do
684
695
defp collect_union ( { :| , _ , [ a , b ] } ) , do: [ b | collect_union ( a ) ]
685
696
defp collect_union ( v ) , do: [ v ]
686
697
698
+ defp validate_kw ( { key , _ } = t , _ ) when is_atom ( key ) , do: t
699
+ defp validate_kw ( _ , original ) do
700
+ raise ArgumentError , message: "unexpected list #{ inspect original } in typespec"
701
+ end
702
+
687
703
defp fn_args ( meta , args , return , vars , caller ) do
688
704
case [ fn_args ( meta , args , vars , caller ) , typespec ( return , vars , caller ) ] do
689
705
[ { :type , _ , :any } , { :type , _ , :any , [ ] } ] -> [ ]
@@ -703,4 +719,19 @@ defmodule Kernel.Typespec do
703
719
defp variable ( { name , meta , _ } ) do
704
720
{ :var , line ( meta ) , name }
705
721
end
722
+
723
+ defp unpack_typespec_kw ( { :type , _ , :union , [
724
+ next ,
725
+ { :type , _ , :tuple , [ { :atom , _ , atom } , type ] }
726
+ ] } , acc ) do
727
+ unpack_typespec_kw ( next , [ { atom , typespec_to_ast ( type ) } | acc ] )
728
+ end
729
+
730
+ defp unpack_typespec_kw ( { :type , _ , :tuple , [ { :atom , _ , atom } , type ] } , acc ) do
731
+ { :ok , [ { atom , typespec_to_ast ( type ) } | acc ] }
732
+ end
733
+
734
+ defp unpack_typespec_kw ( _ , _acc ) do
735
+ :error
736
+ end
706
737
end
0 commit comments