@@ -816,6 +816,7 @@ defmodule Protocol do
816816 # Set up a clear slate to store defined functions
817817 @ __functions__ [ ]
818818 @ fallback_to_any false
819+ @ undefined_impl_description ""
819820
820821 # Invoke the user given block
821822 _ = unquote ( block )
@@ -927,57 +928,101 @@ defmodule Protocol do
927928 end
928929
929930 defp after_defprotocol do
930- quote bind_quoted: [ built_in: built_in ( ) ] do
931- any_impl_for =
932- if @ fallback_to_any do
933- __MODULE__ . Any
934- else
935- nil
936- end
931+ prefix =
932+ quote bind_quoted: [ built_in: built_in ( ) ] do
933+ any_impl_for =
934+ if @ fallback_to_any do
935+ __MODULE__ . Any
936+ else
937+ nil
938+ end
937939
938- # Disable Dialyzer checks - before and after consolidation
939- # the types could be more strict
940- @ dialyzer { :nowarn_function , __protocol__: 1 , impl_for: 1 , impl_for!: 1 }
940+ # Disable Dialyzer checks - before and after consolidation
941+ # the types could be more strict
942+ @ dialyzer { :nowarn_function , __protocol__: 1 , impl_for: 1 , impl_for!: 1 }
941943
942- @ doc false
943- @ spec impl_for ( term ) :: atom | nil
944- Kernel . def ( impl_for ( data ) )
945-
946- # Define the implementation for structs.
947- #
948- # It simply delegates to struct_impl_for which is then
949- # optimized during protocol consolidation.
950- Kernel . def impl_for ( % struct { } ) do
951- struct_impl_for ( struct )
952- end
944+ @ doc false
945+ @ spec impl_for ( term ) :: atom | nil
946+ Kernel . def ( impl_for ( data ) )
947+
948+ # Define the implementation for structs.
949+ #
950+ # It simply delegates to struct_impl_for which is then
951+ # optimized during protocol consolidation.
952+ Kernel . def impl_for ( % struct { } ) do
953+ struct_impl_for ( struct )
954+ end
953955
954- # Define the implementation for built-ins
955- :lists . foreach (
956- fn { mod , guard } ->
957- target = Protocol . __concat__ ( __MODULE__ , mod )
956+ # Define the implementation for built-ins
957+ :lists . foreach (
958+ fn { mod , guard } ->
959+ target = Protocol . __concat__ ( __MODULE__ , mod )
958960
959- Kernel . def impl_for ( data ) when :erlang . unquote ( guard ) ( data ) do
960- case Code . ensure_compiled ( unquote ( target ) ) do
961- { :module , module } -> module
962- { :error , _ } -> unquote ( any_impl_for )
961+ Kernel . def impl_for ( data ) when :erlang . unquote ( guard ) ( data ) do
962+ case Code . ensure_compiled ( unquote ( target ) ) do
963+ { :module , module } -> module
964+ { :error , _ } -> unquote ( any_impl_for )
965+ end
963966 end
967+ end ,
968+ built_in
969+ )
970+
971+ # Define a catch-all impl_for/1 clause to pacify Dialyzer (since
972+ # destructuring opaque types is illegal, Dialyzer will think none of the
973+ # previous clauses matches opaque types, and without this clause, will
974+ # conclude that impl_for can't handle an opaque argument). This is a hack
975+ # since it relies on Dialyzer not being smart enough to conclude that all
976+ # opaque types will get the any_impl_for/0 implementation.
977+ Kernel . def impl_for ( _ ) do
978+ unquote ( any_impl_for )
979+ end
980+
981+ # Internal handler for Structs
982+ Kernel . defp struct_impl_for ( struct ) do
983+ case Code . ensure_compiled ( Protocol . __concat__ ( __MODULE__ , struct ) ) do
984+ { :module , module } -> module
985+ { :error , _ } -> unquote ( any_impl_for )
964986 end
965- end ,
966- built_in
967- )
987+ end
988+
989+ # Inline struct implementation for performance
990+ @ compile { :inline , struct_impl_for: 1 }
991+
992+ if not Module . defines_type? ( __MODULE__ , { :t , 0 } ) do
993+ @ typedoc """
994+ All the types that implement this protocol.
995+ """
996+ @ type t :: term
997+ end
998+
999+ # Store information as an attribute so it
1000+ # can be read without loading the module.
1001+ Module . register_attribute ( __MODULE__ , :__protocol__ , persist: true )
1002+ @ __protocol__ [ fallback_to_any: ! ! @ fallback_to_any ]
1003+
1004+ @ doc false
1005+ @ spec __protocol__ ( :module ) :: __MODULE__
1006+ @ spec __protocol__ ( :functions ) :: [ { atom ( ) , arity ( ) } ]
1007+ @ spec __protocol__ ( :consolidated? ) :: boolean ( )
1008+ @ spec __protocol__ ( :impls ) :: :not_consolidated | { :consolidated , [ module ( ) ] }
1009+ Kernel . def ( __protocol__ ( :module ) , do: __MODULE__ )
1010+ Kernel . def ( __protocol__ ( :functions ) , do: unquote ( :lists . sort ( @ __functions__ ) ) )
1011+ Kernel . def ( __protocol__ ( :consolidated? ) , do: false )
1012+ Kernel . def ( __protocol__ ( :impls ) , do: :not_consolidated )
1013+ end
9681014
969- # Define a catch-all impl_for/1 clause to pacify Dialyzer (since
970- # destructuring opaque types is illegal, Dialyzer will think none of the
971- # previous clauses matches opaque types, and without this clause, will
972- # conclude that impl_for can't handle an opaque argument). This is a hack
973- # since it relies on Dialyzer not being smart enough to conclude that all
974- # opaque types will get the any_impl_for/0 implementation.
975- Kernel . def impl_for ( _ ) do
976- unquote ( any_impl_for )
1015+ raise =
1016+ quote do
1017+ raise ( Protocol.UndefinedError ,
1018+ protocol: __MODULE__ ,
1019+ value: data ,
1020+ description: @ undefined_impl_description
1021+ )
9771022 end
9781023
979- undefined_impl_description =
980- Module . get_attribute ( __MODULE__ , :undefined_impl_description , "" )
1024+ quote generated: true do
1025+ unquote ( prefix )
9811026
9821027 @ doc false
9831028 @ spec impl_for! ( term ) :: atom
@@ -987,47 +1032,9 @@ defmodule Protocol do
9871032 end
9881033 else
9891034 Kernel . def impl_for! ( data ) do
990- impl_for ( data ) ||
991- raise ( Protocol.UndefinedError ,
992- protocol: __MODULE__ ,
993- value: data ,
994- description: unquote ( undefined_impl_description )
995- )
996- end
997- end
998-
999- # Internal handler for Structs
1000- Kernel . defp struct_impl_for ( struct ) do
1001- case Code . ensure_compiled ( Protocol . __concat__ ( __MODULE__ , struct ) ) do
1002- { :module , module } -> module
1003- { :error , _ } -> unquote ( any_impl_for )
1035+ impl_for ( data ) || unquote ( raise )
10041036 end
10051037 end
1006-
1007- # Inline struct implementation for performance
1008- @ compile { :inline , struct_impl_for: 1 }
1009-
1010- if not Module . defines_type? ( __MODULE__ , { :t , 0 } ) do
1011- @ typedoc """
1012- All the types that implement this protocol.
1013- """
1014- @ type t :: term
1015- end
1016-
1017- # Store information as an attribute so it
1018- # can be read without loading the module.
1019- Module . register_attribute ( __MODULE__ , :__protocol__ , persist: true )
1020- @ __protocol__ [ fallback_to_any: ! ! @ fallback_to_any ]
1021-
1022- @ doc false
1023- @ spec __protocol__ ( :module ) :: __MODULE__
1024- @ spec __protocol__ ( :functions ) :: [ { atom ( ) , arity ( ) } ]
1025- @ spec __protocol__ ( :consolidated? ) :: boolean ( )
1026- @ spec __protocol__ ( :impls ) :: :not_consolidated | { :consolidated , [ module ( ) ] }
1027- Kernel . def ( __protocol__ ( :module ) , do: __MODULE__ )
1028- Kernel . def ( __protocol__ ( :functions ) , do: unquote ( :lists . sort ( @ __functions__ ) ) )
1029- Kernel . def ( __protocol__ ( :consolidated? ) , do: false )
1030- Kernel . def ( __protocol__ ( :impls ) , do: :not_consolidated )
10311038 end
10321039 end
10331040
0 commit comments