@@ -422,6 +422,17 @@ defmodule Kernel.Typespec do
422422 { :{} , [ line: line ] , args }
423423 end
424424
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+
425436 defp typespec_to_ast ( { :type , line , :binary , [ arg1 , arg2 ] } ) do
426437 [ arg1 , arg2 ] = lc arg inlist [ arg1 , arg2 ] , do: typespec_to_ast ( arg )
427438 cond do
@@ -473,7 +484,7 @@ defmodule Kernel.Typespec do
473484 { var , line , nil }
474485 end
475486
476- # special shortcut(s)
487+ # Special shortcut(s)
477488 defp typespec_to_ast ( { :remote_type , line , [ { :atom , _ , :elixir } , { :atom , _ , :char_list } , [ ] ] } ) do
478489 typespec_to_ast ( { :type , line , :char_list , [ ] } )
479490 end
@@ -482,7 +493,6 @@ defmodule Kernel.Typespec do
482493 typespec_to_ast ( { :type , line , :as_boolean , [ arg ] } )
483494 end
484495
485-
486496 defp typespec_to_ast ( { :remote_type , line , [ mod , name , args ] } ) do
487497 args = lc arg inlist args , do: typespec_to_ast ( arg )
488498 dot = { :. , [ line: line ] , [ typespec_to_ast ( mod ) , typespec_to_ast ( name ) ] }
@@ -524,7 +534,7 @@ defmodule Kernel.Typespec do
524534
525535 # Handle unions
526536 defp typespec ( { :| , meta , [ _ , _ ] } = exprs , vars , caller ) do
527- exprs = :lists . reverse ( collect_union ( exprs ) )
537+ exprs = Enum . reverse ( collect_union ( exprs ) )
528538 union = lc e inlist exprs , do: typespec ( e , vars , caller )
529539 { :type , line ( meta ) , :union , union }
530540 end
@@ -558,7 +568,6 @@ defmodule Kernel.Typespec do
558568 end
559569
560570 # Handle funs
561-
562571 defp typespec ( { :-> , meta , [ { [ { :fun , _ , arguments } ] , return } ] } , vars , caller ) when is_list ( arguments ) do
563572 typespec ( { :-> , meta , [ { arguments , return } ] } , vars , caller )
564573 end
@@ -609,7 +618,6 @@ defmodule Kernel.Typespec do
609618 end
610619
611620 # Handle blocks
612-
613621 defp typespec ( { :__block__ , _meta , [ arg ] } , vars , caller ) do
614622 typespec ( arg , vars , caller )
615623 end
@@ -665,8 +673,11 @@ defmodule Kernel.Typespec do
665673 typespec ( { :nonempty_list , [ ] , [ spec ] } , vars , caller )
666674 end
667675
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 )
670681 end
671682
672683 defp typespec ( t , vars , caller ) when is_tuple ( t ) do
@@ -684,6 +695,11 @@ defmodule Kernel.Typespec do
684695 defp collect_union ( { :| , _ , [ a , b ] } ) , do: [ b | collect_union ( a ) ]
685696 defp collect_union ( v ) , do: [ v ]
686697
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+
687703 defp fn_args ( meta , args , return , vars , caller ) do
688704 case [ fn_args ( meta , args , vars , caller ) , typespec ( return , vars , caller ) ] do
689705 [ { :type , _ , :any } , { :type , _ , :any , [ ] } ] -> [ ]
@@ -703,4 +719,19 @@ defmodule Kernel.Typespec do
703719 defp variable ( { name , meta , _ } ) do
704720 { :var , line ( meta ) , name }
705721 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
706737end
0 commit comments