@@ -366,24 +366,20 @@ defmodule Protocol do
366366 abstract_types = :erl_parse . abstract ( :lists . usort ( types ) )
367367
368368 clauses =
369- :lists . map (
370- fn
371- { :clause , l , [ { :atom , _ , :consolidated? } ] , [ ] , [ { :atom , _ , _ } ] } ->
372- { :clause , l , [ { :atom , 0 , :consolidated? } ] , [ ] , [ { :atom , 0 , true } ] }
369+ Enum . map ( clauses , fn
370+ { :clause , l , [ { :atom , _ , :consolidated? } ] , [ ] , [ { :atom , _ , _ } ] } ->
371+ { :clause , l , [ { :atom , 0 , :consolidated? } ] , [ ] , [ { :atom , 0 , true } ] }
373372
374- { :clause , l , [ { :atom , _ , :impls } ] , [ ] , [ { :atom , _ , _ } ] } ->
375- tuple = { :tuple , 0 , [ { :atom , 0 , :consolidated } , abstract_types ] }
376- { :clause , l , [ { :atom , 0 , :impls } ] , [ ] , [ tuple ] }
373+ { :clause , l , [ { :atom , _ , :impls } ] , [ ] , [ { :atom , _ , _ } ] } ->
374+ tuple = { :tuple , 0 , [ { :atom , 0 , :consolidated } , abstract_types ] }
375+ { :clause , l , [ { :atom , 0 , :impls } ] , [ ] , [ tuple ] }
377376
378- { :clause , _ , _ , _ , _ } = c ->
379- c
380- end ,
381- clauses
382- )
377+ { :clause , _ , _ , _ , _ } = c ->
378+ c
379+ end )
383380
384- change_impl_for ( tail , protocol , types , structs , true , [
385- { :function , line , :__protocol__ , 1 , clauses } | acc
386- ] )
381+ acc = [ { :function , line , :__protocol__ , 1 , clauses } | acc ]
382+ change_impl_for ( tail , protocol , types , structs , true , acc )
387383 end
388384
389385 defp change_impl_for (
@@ -404,9 +400,8 @@ defmodule Protocol do
404400 clauses =
405401 [ struct_clause_for ( line ) | clauses ] ++ [ fallback_clause_for ( fallback , protocol , line ) ]
406402
407- change_impl_for ( tail , protocol , types , structs , protocol? , [
408- { :function , line , :impl_for , 1 , clauses } | acc
409- ] )
403+ acc = [ { :function , line , :impl_for , 1 , clauses } | acc ]
404+ change_impl_for ( tail , protocol , types , structs , protocol? , acc )
410405 end
411406
412407 defp change_impl_for (
@@ -549,6 +544,13 @@ defmodule Protocol do
549544
550545 defp after_defprotocol do
551546 quote bind_quoted: [ builtin: __builtin__ ( ) ] do
547+ any_impl_for =
548+ if @ fallback_to_any do
549+ quote do: unquote ( __MODULE__ . Any ) . __impl__ ( :target )
550+ else
551+ nil
552+ end
553+
552554 @ doc false
553555 @ spec impl_for ( term ) :: atom | nil
554556 Kernel . def ( impl_for ( data ) )
@@ -567,9 +569,10 @@ defmodule Protocol do
567569 target = Module . concat ( __MODULE__ , mod )
568570
569571 Kernel . def impl_for ( data ) when :erlang . unquote ( guard ) ( data ) do
570- case impl_for? ( unquote ( target ) ) do
572+ case Code . ensure_compiled? ( unquote ( target ) ) and
573+ function_exported? ( unquote ( target ) , :__impl__ , 1 ) do
571574 true -> unquote ( target ) . __impl__ ( :target )
572- false -> any_impl_for ( )
575+ false -> unquote ( any_impl_for )
573576 end
574577 end
575578 end ,
@@ -583,39 +586,33 @@ defmodule Protocol do
583586 # since it relies on Dialyzer not being smart enough to conclude that all
584587 # opaque types will get the any_impl_for/0 implementation.
585588 Kernel . def impl_for ( _ ) do
586- any_impl_for ( )
589+ unquote ( any_impl_for )
587590 end
588591
589592 @ doc false
590- @ spec impl_for! ( term ) :: atom | no_return
591- Kernel . def impl_for! ( data ) do
592- impl_for ( data ) || raise ( Protocol.UndefinedError , protocol: __MODULE__ , value: data )
593- end
594-
595- # Internal handler for Any
596- if @ fallback_to_any do
597- Kernel . defp ( any_impl_for ( ) , do: __MODULE__ . Any . __impl__ ( :target ) )
593+ @ spec impl_for! ( term ) :: atom
594+ if any_impl_for do
595+ Kernel . def impl_for! ( data ) do
596+ impl_for ( data )
597+ end
598598 else
599- Kernel . defp ( any_impl_for ( ) , do: nil )
599+ Kernel . def impl_for! ( data ) do
600+ impl_for ( data ) || raise ( Protocol.UndefinedError , protocol: __MODULE__ , value: data )
601+ end
600602 end
601603
602604 # Internal handler for Structs
603605 Kernel . defp struct_impl_for ( struct ) do
604606 target = Module . concat ( __MODULE__ , struct )
605607
606- case impl_for ?( target ) do
608+ case Code . ensure_compiled ?( target ) and function_exported? ( target , :__impl__ , 1 ) do
607609 true -> target . __impl__ ( :target )
608- false -> any_impl_for ( )
610+ false -> unquote ( any_impl_for )
609611 end
610612 end
611613
612- # Check if compilation is available internally
613- Kernel . defp impl_for? ( target ) do
614- Code . ensure_compiled? ( target ) and function_exported? ( target , :__impl__ , 1 )
615- end
616-
617- # Inline any and struct implementations
618- @ compile { :inline , any_impl_for: 0 , struct_impl_for: 1 , impl_for?: 1 }
614+ # Inline struct implementation for performance
615+ @ compile { :inline , struct_impl_for: 1 }
619616
620617 unless Kernel.Typespec . defines_type? ( __MODULE__ , :t , 0 ) do
621618 @ type t :: term
0 commit comments