@@ -54,9 +54,10 @@ defmodule Protocol do
54
54
target = Module . concat ( __MODULE__ , mod )
55
55
56
56
Kernel . def impl_for ( data ) when :erlang . unquote ( guard ) ( data ) do
57
- unquote ( target ) . __impl__ ( :name )
58
- catch :error , :undef , [ [ { unquote ( target ) , :__impl__ , [ :name ] , _ } | _ ] | _ ] ->
59
- any_impl_for
57
+ case impl_for? ( unquote ( target ) ) do
58
+ true -> unquote ( target ) . __impl__ ( :name )
59
+ false -> any_impl_for
60
+ end
60
61
end
61
62
end
62
63
@@ -68,10 +69,10 @@ defmodule Protocol do
68
69
# Internal handler for Any
69
70
if @ fallback_to_any do
70
71
Kernel . defp any_impl_for do
71
- __MODULE__ . Any . __impl__ ( :name )
72
- catch
73
- :error , :undef , [ [ { __MODULE__ . Any , :__impl__ , [ :name ] , _ } | _ ] | _ ] ->
74
- nil
72
+ case impl_for? ( __MODULE__ . Any ) do
73
+ true -> __MODULE__ . Any . __impl__ ( :name )
74
+ false -> nil
75
+ end
75
76
end
76
77
else
77
78
Kernel . defp any_impl_for , do: nil
@@ -80,15 +81,20 @@ defmodule Protocol do
80
81
# Internal handler for Structs
81
82
Kernel . defp struct_impl_for ( struct ) do
82
83
target = Module . concat ( __MODULE__ , struct )
83
- try do
84
- target . __impl__ ( :name )
85
- catch :error , :undef , [ [ { ^ target , :__impl__ , [ :name ] , _ } | _ ] | _ ] ->
86
- any_impl_for
84
+ case impl_for? ( target ) do
85
+ true -> target . __impl__ ( :name )
86
+ false -> any_impl_for
87
87
end
88
88
end
89
89
90
+ # Check if compilation is available internally
91
+ Kernel . defp impl_for? ( target ) do
92
+ Code . ensure_compiled? ( target ) and
93
+ function_exported? ( target , :__impl__ , 1 )
94
+ end
95
+
90
96
# Inline any and struct implementations
91
- @ compile { :inline , any_impl_for: 0 , struct_impl_for: 1 }
97
+ @ compile { :inline , any_impl_for: 0 , struct_impl_for: 1 , impl_for?: 1 }
92
98
93
99
if :code . ensure_loaded ( Kernel.Typespec ) == { :module , Kernel.Typespec } and
94
100
not Kernel.Typespec . defines_type? ( __MODULE__ , :t , 0 ) do
@@ -162,17 +168,17 @@ defmodule Protocol do
162
168
# Builtin types.
163
169
@ doc false
164
170
def builtin do
165
- [ is_tuple: Tuple ,
166
- is_atom: Atom ,
167
- is_list: List ,
168
- is_map: Map ,
169
- is_bitstring: BitString ,
170
- is_integer: Integer ,
171
- is_float: Float ,
172
- is_function: Function ,
173
- is_pid: PID ,
174
- is_port: Port ,
175
- is_reference: Reference ]
171
+ [ is_tuple: Tuple ,
172
+ is_atom: Atom ,
173
+ is_list: List ,
174
+ is_map: Map ,
175
+ is_bitstring: BitString ,
176
+ is_integer: Integer ,
177
+ is_float: Float ,
178
+ is_function: Function ,
179
+ is_pid: PID ,
180
+ is_port: Port ,
181
+ is_reference: Reference ]
176
182
end
177
183
178
184
# Implements the function that detects the protocol and
@@ -184,10 +190,9 @@ defmodule Protocol do
184
190
target = Module . concat ( current , Tuple )
185
191
186
192
fallback = quote do
187
- try do
188
- unquote ( target ) . __impl__ ( :name )
189
- catch :error , :undef , [ [ { unquote ( target ) , :__impl__ , [ :name ] , _ } | _ ] | _ ] ->
190
- any_impl_for
193
+ case impl_for? ( unquote ( target ) ) do
194
+ true -> unquote ( target ) . __impl__ ( :name )
195
+ false -> any_impl_for
191
196
end
192
197
end
193
198
@@ -197,11 +202,9 @@ defmodule Protocol do
197
202
case not ( atom in unquote ( all ) ) and match? ( 'Elixir.' ++ _ , atom_to_list ( atom ) ) do
198
203
true ->
199
204
target = Module . concat ( unquote ( current ) , atom )
200
- try do
201
- target . __impl__ ( :name )
202
- catch
203
- :error , :undef , [ [ { ^ target , :__impl__ , [ :name ] , _ } | _ ] | _ ] ->
204
- unquote ( fallback )
205
+ case impl_for? ( target ) do
206
+ true -> target . __impl__ ( :name )
207
+ false -> unquote ( fallback )
205
208
end
206
209
false ->
207
210
unquote ( fallback )
0 commit comments