@@ -366,24 +366,20 @@ defmodule Protocol do
366
366
abstract_types = :erl_parse . abstract ( :lists . usort ( types ) )
367
367
368
368
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 } ] }
373
372
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 ] }
377
376
378
- { :clause , _ , _ , _ , _ } = c ->
379
- c
380
- end ,
381
- clauses
382
- )
377
+ { :clause , _ , _ , _ , _ } = c ->
378
+ c
379
+ end )
383
380
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 )
387
383
end
388
384
389
385
defp change_impl_for (
@@ -404,9 +400,8 @@ defmodule Protocol do
404
400
clauses =
405
401
[ struct_clause_for ( line ) | clauses ] ++ [ fallback_clause_for ( fallback , protocol , line ) ]
406
402
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 )
410
405
end
411
406
412
407
defp change_impl_for (
@@ -549,6 +544,13 @@ defmodule Protocol do
549
544
550
545
defp after_defprotocol do
551
546
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
+
552
554
@ doc false
553
555
@ spec impl_for ( term ) :: atom | nil
554
556
Kernel . def ( impl_for ( data ) )
@@ -567,9 +569,10 @@ defmodule Protocol do
567
569
target = Module . concat ( __MODULE__ , mod )
568
570
569
571
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
571
574
true -> unquote ( target ) . __impl__ ( :target )
572
- false -> any_impl_for ( )
575
+ false -> unquote ( any_impl_for )
573
576
end
574
577
end
575
578
end ,
@@ -583,39 +586,33 @@ defmodule Protocol do
583
586
# since it relies on Dialyzer not being smart enough to conclude that all
584
587
# opaque types will get the any_impl_for/0 implementation.
585
588
Kernel . def impl_for ( _ ) do
586
- any_impl_for ( )
589
+ unquote ( any_impl_for )
587
590
end
588
591
589
592
@ 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
598
598
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
600
602
end
601
603
602
604
# Internal handler for Structs
603
605
Kernel . defp struct_impl_for ( struct ) do
604
606
target = Module . concat ( __MODULE__ , struct )
605
607
606
- case impl_for ?( target ) do
608
+ case Code . ensure_compiled ?( target ) and function_exported? ( target , :__impl__ , 1 ) do
607
609
true -> target . __impl__ ( :target )
608
- false -> any_impl_for ( )
610
+ false -> unquote ( any_impl_for )
609
611
end
610
612
end
611
613
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 }
619
616
620
617
unless Kernel.Typespec . defines_type? ( __MODULE__ , :t , 0 ) do
621
618
@ type t :: term
0 commit comments